From 558c99e833a5ca1a86fa0ed436159cdc09e94fa3 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Mon, 5 Oct 2026 03:25:30 +0530 Subject: [PATCH 01/52] feat(swift-lang): add OpenUI Lang parser for Swift Ports lang-core's parsing pipeline to a Swift package (OpenUILang): lexer, statement splitter and auto-close, Pratt expression parser, schema-aware materialization and validation, the batch parser and the incremental streaming parser. The port keeps the JavaScript semantics the TypeScript code relies on: UTF-16 indexing, JSON.parse string unescaping (with its fallback for malformed escapes), Number to String formatting, loose equality, truthiness, undefined versus null, and JavaScript object key order. Conformance fixtures are generated from @openuidev/lang-core by Scripts/generate-fixtures.mjs: 55 inputs (the chat library prompt examples plus edge cases) for batch parsing, streaming checkpoints for each, and StreamParser.set() sequences. The Swift tests compare against them. --- packages/swift-lang/.gitignore | 2 + packages/swift-lang/Package.swift | 20 + .../swift-lang/Scripts/generate-fixtures.mjs | 257 + .../swift-lang/Sources/OpenUILang/AST.swift | 132 + .../Sources/OpenUILang/Builtins.swift | 292 + .../Sources/OpenUILang/Expressions.swift | 224 + .../swift-lang/Sources/OpenUILang/JSON.swift | 424 ++ .../Sources/OpenUILang/JSSemantics.swift | 257 + .../swift-lang/Sources/OpenUILang/Lexer.swift | 314 + .../Sources/OpenUILang/Materialize.swift | 267 + .../Sources/OpenUILang/Parser.swift | 543 ++ .../Sources/OpenUILang/Statements.swift | 136 + .../swift-lang/Sources/OpenUILang/Types.swift | 223 + .../Sources/OpenUILang/Validation.swift | 313 + .../swift-lang/Sources/OpenUILang/Value.swift | 142 + .../Sources/OpenUISwiftUI/Exports.swift | 1 + .../Tests/OpenUILangTests/Fixtures.swift | 67 + .../OpenUILangTests/Fixtures/parser.json | 5659 +++++++++++++++++ .../OpenUILangTests/Fixtures/schemas.json | 4363 +++++++++++++ .../OpenUILangTests/Fixtures/stream-set.json | 669 ++ .../OpenUILangTests/Fixtures/streaming.json | 1 + .../OpenUILangTests/JSSemanticsTests.swift | 64 + .../ParserConformanceTests.swift | 47 + 23 files changed, 14417 insertions(+) create mode 100644 packages/swift-lang/.gitignore create mode 100644 packages/swift-lang/Package.swift create mode 100644 packages/swift-lang/Scripts/generate-fixtures.mjs create mode 100644 packages/swift-lang/Sources/OpenUILang/AST.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Builtins.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Expressions.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/JSON.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/JSSemantics.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Lexer.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Materialize.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Parser.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Statements.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Types.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Validation.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Value.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Exports.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/Fixtures.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json create mode 100644 packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json create mode 100644 packages/swift-lang/Tests/OpenUILangTests/Fixtures/stream-set.json create mode 100644 packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json create mode 100644 packages/swift-lang/Tests/OpenUILangTests/JSSemanticsTests.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/ParserConformanceTests.swift diff --git a/packages/swift-lang/.gitignore b/packages/swift-lang/.gitignore new file mode 100644 index 0000000000..2d9f16e2d2 --- /dev/null +++ b/packages/swift-lang/.gitignore @@ -0,0 +1,2 @@ +.build/ +.swiftpm/ diff --git a/packages/swift-lang/Package.swift b/packages/swift-lang/Package.swift new file mode 100644 index 0000000000..49444d1584 --- /dev/null +++ b/packages/swift-lang/Package.swift @@ -0,0 +1,20 @@ +// swift-tools-version:6.0 +import PackageDescription + +let package = Package( + name: "OpenUI", + platforms: [.iOS(.v17), .macOS(.v14)], + products: [ + .library(name: "OpenUILang", targets: ["OpenUILang"]), + .library(name: "OpenUISwiftUI", targets: ["OpenUISwiftUI"]), + ], + targets: [ + .target(name: "OpenUILang"), + .target(name: "OpenUISwiftUI", dependencies: ["OpenUILang"]), + .testTarget( + name: "OpenUILangTests", + dependencies: ["OpenUILang"], + resources: [.copy("Fixtures")] + ), + ] +) diff --git a/packages/swift-lang/Scripts/generate-fixtures.mjs b/packages/swift-lang/Scripts/generate-fixtures.mjs new file mode 100644 index 0000000000..eeb1c9c208 --- /dev/null +++ b/packages/swift-lang/Scripts/generate-fixtures.mjs @@ -0,0 +1,257 @@ +// Regenerates the conformance fixtures in Tests/OpenUILangTests/Fixtures from +// the TypeScript implementation, which is the source of truth. +// +// pnpm run build:packages +// node packages/swift-lang/Scripts/generate-fixtures.mjs +// +// Each fixture pairs an input with what @openuidev/lang-core produces for it. +// The Swift tests feed the same input to the Swift port and compare. + +import { mkdirSync, writeFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const here = dirname(fileURLToPath(import.meta.url)); +const packages = join(here, "..", ".."); +const fixtures = join(here, "..", "Tests", "OpenUILangTests", "Fixtures"); + +// Fixture generation is not product usage, so keep lang-core's telemetry off. +process.env.OPENUI_TELEMETRY_DISABLED = "1"; + +const core = await import(join(packages, "lang-core", "dist", "index.mjs")); +const ui = await import(join(packages, "react-ui", "dist", "genui-lib", "index.mjs")); + +// ── Schemas ─────────────────────────────────────────────────────────────── + +const chatSchema = ui.openuiChatLibrary.toJSONSchema(); + +// Small hand-written schema that exercises validation paths the chat library +// doesn't: defaults, const, integer, nested required keys, enum defaults. +const testSchema = { + $defs: { + Card: { + properties: { + children: { + type: "array", + items: { anyOf: [{ $ref: "#/$defs/Text" }, { $ref: "#/$defs/Button" }, { $ref: "#/$defs/Chart" }] }, + }, + title: { type: "string" }, + }, + required: ["children"], + }, + Text: { + properties: { + text: { type: "string" }, + size: { type: "string", enum: ["s", "m", "l"], default: "m" }, + }, + required: ["text"], + }, + Button: { + properties: { + label: { type: "string" }, + action: {}, + variant: { type: "string", enum: ["primary", "secondary"] }, + }, + required: ["label"], + }, + Input: { + properties: { name: { type: "string" }, value: { type: "string" } }, + required: ["name"], + }, + Chart: { + properties: { + labels: { type: "array", items: { type: "string" } }, + values: { type: "array", items: { type: "number" } }, + meta: { + type: "object", + properties: { unit: { type: "string" }, scale: { type: "number", default: 1 } }, + required: ["unit"], + }, + }, + required: ["labels", "values"], + }, + Tagged: { + properties: { + count: { type: "integer" }, + flag: { type: "boolean" }, + kind: { const: "x" }, + tone: { type: "string", default: "neutral" }, + }, + required: ["tone"], + }, + }, +}; + +const schemas = { chat: { schema: chatSchema, root: "Card" }, test: { schema: testSchema, root: "Card" } }; + +// ── Corpus ──────────────────────────────────────────────────────────────── + +const chatExamples = ui.openuiChatPromptOptions.examples.map((text, i) => ({ + name: `chat-example-${i + 1}`, + schema: "chat", + input: text, +})); + +const t = (name, input) => ({ name, schema: "test", input }); + +const edgeCases = [ + t("basic", 'root = Card([t1, b1])\nt1 = Text("Hi")\nb1 = Button("Go")'), + t("missing-required", 'root = Card([t1, b1])\nt1 = Text()\nb1 = Button("Go")'), + t("null-required-with-default", "root = Card([t1])\nt1 = Text(null)"), + t("required-default-fills", 'root = Card([x])\nx = Tagged(1, true, "x", null)'), + t("unknown-component", 'root = Card([Mystery("a"), Text("b")])'), + t("excess-args", 'root = Card([Text("a", "m", "extra", 4)])'), + t("type-mismatch-scalar", 'root = Card([Text(42)], 7)'), + t("enum-mismatch", 'root = Card([Text("a", "xl"), Button("b", null, "tertiary")])'), + t("enum-partial-deferred", 'root = Card([Text("a", "x'), + t("integer-boolean-const", 'root = Card([x])\nx = Tagged(1.5, "yes", "y", "loud")'), + t( + "nested-object", + 'root = Card([c1, c2, c3])\nc1 = Chart(["a"], [1], {unit: "kg"})\nc2 = Chart(["a"], [1], {scale: 2})\nc3 = Chart(["a"], [1], {unit: 5, scale: "big"})', + ), + t("array-items-pruned", 'root = Card([Chart(["a", 2, "c"], [1, "x", 3])])'), + t("element-in-data-slot", 'root = Card([Chart([Text("a")], [1])])'), + t("unresolved-and-orphaned", "root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")"), + t("cycle", "root = Card([a])\na = Card([b])\nb = Card([a])"), + t("self-reference", "root = Card([root])"), + t("no-root-first-component", 'x = 1\nmain = Card([Text("a")])\nother = Card([])'), + t("root-name-statement", 'Card = Card([Text("named")])\nother = Card([])'), + t("duplicate-ids", 'root = Card([a])\na = Text("first")\na = Text("second")'), + t("only-prose", "Here is your UI, it will appear below."), + t("empty", ""), + t("whitespace", " \n\t \n"), + t( + "fences-and-prose", + 'Sure! Here it is:\n```openui\nroot = Card([a])\na = Text("fenced")\n```\nAnything else?', + ), + t("multiple-fences", '```\nroot = Card([a])\n```\nand\n```\na = Text("second block")\n```'), + t("unclosed-fence", '```openui\nroot = Card([a])\na = Text("str'), + t("fence-in-string", 'root = Card([a])\na = Text("use ``` to fence")'), + t( + "comments", + 'root = Card([a]) // trailing\n# full line\na = Text("not // a comment # here")\n// done', + ), + t("crlf", 'root = Card([a])\r\na = Text("windows")\r\n'), + t( + "string-escapes", + 'root = Card([a, b, c, d])\na = Text("tab\\tnew\\nquote\\" back\\\\ uni\\u00e9 pair\\ud83d\\ude00")\nb = Text(\'single \\\' quote \\n esc \\q\')\nc = Text("bad \\x escape")\nd = Text("emoji 😀 and é and 漢字")', + ), + t("emoji-outside-strings", 'root = Card([a]) 😀\na = Text("ok") ✅'), + t("unterminated-string", 'root = Card([a])\na = Text("streaming tex'), + t("unterminated-escape", 'root = Card([a])\na = Text("ends with \\'), + t( + "numbers", + 'root = Card([Chart(["a","b","c","d","e","f"], [-3, 1.5, 1e3, 007, -0, 2.5e-3])])\n$x = 1e\n$y = 1E+2\n$z = 3.', + ), + t( + "operators", + '$a = 1\n$b = "2"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == "1" ? "yes" : "no")])', + ), + t( + "multiline-ternary", + '$on = true\nroot = Card([t])\nt = Text($on\n ? "enabled"\n : "disabled")', + ), + t( + "member-index", + '$data = {rows: [{name: "a"}, {name: "b"}], "key x": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data["key x"])])', + ), + t( + "builtins", + '$items = [3, 1, 2]\nroot = Card([Text("" + @Count($items)), Text("" + @Sum($items)), Text(@Round(2.555, 2) + "")])\nbare = Count($items)', + ), + t( + "actions", + '$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button("Inc", Action([@Set($n, $n + 1), @ToAssistant("Bumped", "ctx")]))\nb2 = Button("Reset", Action([@Reset($n)]))\nb3 = Button("Docs", Action([@OpenUrl("https://openui.com")]))', + ), + t( + "each", + '$todos = [{title: "a", done: false}, {title: "b", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))', + ), + t( + "query-mutation", + '$q = "x"\nusers = Query("list_users", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation("save_user", {name: $q})\nroot = Card([Text(users.rows.length + " users"), Button("Save", Action([@Run(save), @Run(users)]))])', + ), + t("state-query", '$data = Query("get", {})\nroot = Card([Text("x")])'), + t("inline-query", 'root = Card([Text(Query("get", {}))])'), + t("assignment", '$v = ""\nroot = Card([Input("name", $v = $value)])'), + t( + "object-key-order", + '$o = {b: 1, 2: "two", a: 3, 1: "one", "10": 10}\nroot = Card([Text("x")])', + ), + t("missing-commas", 'root = Card([Text("a") Text("b"), Text("c"),])'), + t("lowercase-builtin-name", 'root = Card([Text(@first([1]))])'), + t("unknown-tokens", "root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo"), + t( + "combining-characters", + 'root = Card([Text("e\\u0301 cafe\\u0301"), Text("한국어"), Text("ok")])', + ), + t("truncated-mid-call", 'root = Card([a, b])\na = Text("one")\nb = Button("tw'), + t("truncated-mid-object", 'root = Card([Chart(["a"], [1], {unit: "k'), +]; + +// ── Fixture generation ──────────────────────────────────────────────────── + +function parseWith(schemaName, input) { + const { schema, root } = schemas[schemaName]; + return core.createParser(schema, root).parse(input); +} + +/** UTF-16 offsets that don't split a surrogate pair. */ +function safeOffsets(text, step) { + const offsets = []; + for (let i = step; i < text.length; i += step) { + let at = i; + const code = text.charCodeAt(at - 1); + if (code >= 0xd800 && code <= 0xdbff) at += 1; + offsets.push(at); + } + offsets.push(text.length); + return [...new Set(offsets)]; +} + +function streamCheckpoints(schemaName, input) { + const { schema, root } = schemas[schemaName]; + const parser = core.createStreamingParser(schema, root); + const step = Math.max(1, Math.ceil(input.length / 12)); + let last = 0; + return safeOffsets(input, step).map((at) => { + const result = parser.push(input.slice(last, at)); + last = at; + return { at, expected: result }; + }); +} + +const parserCases = [...chatExamples, ...edgeCases].map((c) => ({ + ...c, + expected: parseWith(c.schema, c.input), +})); + +const streamingCases = [...chatExamples, ...edgeCases] + .filter((c) => c.input.length > 0) + .map((c) => ({ ...c, checkpoints: streamCheckpoints(c.schema, c.input) })); + +// `set()` with appended text, then replaced text (which resets the parser). +const setCases = edgeCases.slice(0, 6).map((c) => { + const { schema, root } = schemas[c.schema]; + const parser = core.createStreamingParser(schema, root); + const half = c.input.slice(0, Math.floor(c.input.length / 2)); + const steps = [half, c.input, 'root = Card([Text("replaced")])'].map((text) => ({ + text, + expected: parser.set(text), + })); + return { name: c.name, schema: c.schema, steps }; +}); + +function write(name, data, indent = 1) { + mkdirSync(fixtures, { recursive: true }); + writeFileSync(join(fixtures, name), JSON.stringify(data, null, indent) + "\n"); +} + +write("schemas.json", Object.fromEntries(Object.entries(schemas))); +write("parser.json", parserCases); +write("streaming.json", streamingCases, 0); +write("stream-set.json", setCases); + +console.log( + `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set fixtures`, +); diff --git a/packages/swift-lang/Sources/OpenUILang/AST.swift b/packages/swift-lang/Sources/OpenUILang/AST.swift new file mode 100644 index 0000000000..34a25ccf24 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/AST.swift @@ -0,0 +1,132 @@ +/// Every value that can appear in an OpenUI Lang expression. +/// +/// Mirrors lang-core's `ASTNode` union. Literal and structural nodes are lowered +/// to plain values by the materializer; the reactive and operator nodes survive +/// into props and are resolved by the evaluator at runtime. +public indirect enum ASTNode: Sendable, Equatable { + /// A component or builtin call: `Header("Hello")`, `@Count(items)`. + /// `mappedProps` holds the arguments keyed by prop name for catalog + /// components inside runtime expressions. + case comp(name: String, args: [ASTNode], mappedProps: [ASTEntry]?) + case str(String) + case num(Double) + case bool(Bool) + case null + case arr([ASTNode]) + case obj([ASTEntry]) + /// A reference to another statement. + case ref(String) + /// A placeholder for a reference that could not be resolved. + case ph(String) + /// A reactive state variable, including the `$`: `$count`. + case stateRef(String) + /// A Query or Mutation result, resolved at runtime. + case runtimeRef(String, refType: RuntimeRefType) + case binOp(op: String, left: ASTNode, right: ASTNode) + case unaryOp(op: String, operand: ASTNode) + case ternary(cond: ASTNode, then: ASTNode, else: ASTNode) + case member(obj: ASTNode, field: String) + case index(obj: ASTNode, index: ASTNode) + case assign(target: String, value: ASTNode) + + /// The discriminant lang-core stores in `k`. + public var kind: String { + switch self { + case .comp: return "Comp" + case .str: return "Str" + case .num: return "Num" + case .bool: return "Bool" + case .null: return "Null" + case .arr: return "Arr" + case .obj: return "Obj" + case .ref: return "Ref" + case .ph: return "Ph" + case .stateRef: return "StateRef" + case .runtimeRef: return "RuntimeRef" + case .binOp: return "BinOp" + case .unaryOp: return "UnaryOp" + case .ternary: return "Ternary" + case .member: return "Member" + case .index: return "Index" + case .assign: return "Assign" + } + } + + /// Nodes that must survive parser lowering for runtime evaluation. + public var isRuntimeExpr: Bool { + switch self { + case .stateRef, .runtimeRef, .binOp, .unaryOp, .ternary, .member, .index, .assign: + return true + default: + return false + } + } + + /// Visits this node and every node below it, depth first. + public func walk(_ visit: (ASTNode) -> Void) { + visit(self) + switch self { + case .comp(_, let args, let mappedProps): + for arg in args { arg.walk(visit) } + for entry in mappedProps ?? [] { entry.value.walk(visit) } + case .arr(let elements): + for element in elements { element.walk(visit) } + case .obj(let entries): + for entry in entries { entry.value.walk(visit) } + case .binOp(_, let left, let right): + left.walk(visit) + right.walk(visit) + case .unaryOp(_, let operand): + operand.walk(visit) + case .ternary(let cond, let then, let otherwise): + cond.walk(visit) + then.walk(visit) + otherwise.walk(visit) + case .member(let obj, _): + obj.walk(visit) + case .index(let obj, let index): + obj.walk(visit) + index.walk(visit) + case .assign(_, let value): + value.walk(visit) + default: + break + } + } +} + +public struct ASTEntry: Sendable, Equatable { + public var key: String + public var value: ASTNode + + public init(_ key: String, _ value: ASTNode) { + self.key = key + self.value = value + } +} + +public enum RuntimeRefType: String, Sendable, Equatable { + case query + case mutation +} + +/// A call extracted from a Query or Mutation statement. +public struct CallNode: Sendable, Equatable { + public var callee: String + public var args: [ASTNode] +} + +/// A statement classified at parse time from its identifier token and expression shape. +public enum Statement: Sendable, Equatable { + case value(id: String, expr: ASTNode) + case state(id: String, initial: ASTNode) + case query(id: String, call: CallNode, expr: ASTNode, deps: [String]?) + case mutation(id: String, call: CallNode, expr: ASTNode) + + public var id: String { + switch self { + case .value(let id, _), .state(let id, _), .query(let id, _, _, _), .mutation(let id, _, _): + return id + } + } +} diff --git a/packages/swift-lang/Sources/OpenUILang/Builtins.swift b/packages/swift-lang/Sources/OpenUILang/Builtins.swift new file mode 100644 index 0000000000..96c44e6af9 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Builtins.swift @@ -0,0 +1,292 @@ +import Foundation + +/// A data builtin callable as `@Name(...)`: its prompt documentation and implementation. +public struct BuiltinDef: Sendable { + public var name: String + /// Signature for prompt docs: `Count(array) → number`. + public var signature: String + public var description: String + public var fn: @Sendable ([OpenUIValue]) -> OpenUIValue +} + +private func arg(_ args: [OpenUIValue], _ index: Int) -> OpenUIValue { + index < args.count ? args[index] : .undefined +} + +/// `String(x ?? "")`. +private func stringOrEmpty(_ value: OpenUIValue) -> String { + value.isNullish ? "" : value.jsString +} + +/// JavaScript property access (`obj[key]`) on plain values. +func jsProperty(_ value: OpenUIValue, _ key: String) -> OpenUIValue { + switch value { + case .object(let object): + return object[key] ?? .undefined + case .array(let items): + if key == "length" { return .number(Double(items.count)) } + if let index = Int(key), String(index) == key, index >= 0, index < items.count { + return items[index] + } + return .undefined + case .string(let string): + let units = Array(string.utf16) + if key == "length" { return .number(Double(units.count)) } + if let index = Int(key), String(index) == key, index >= 0, index < units.count { + return .string(String(decoding: [units[index]], as: UTF16.self)) + } + return .undefined + case .element(let element): + switch key { + case "type": return "element" + case "typeName": return .string(element.typeName) + case "props": return .object(element.props) + case "partial": return .bool(element.partial) + case "statementId": return element.statementId.map { .string($0) } ?? .undefined + default: return .undefined + } + default: + return .undefined + } +} + +/// `String.prototype.includes`, which compares UTF-16 code units (Swift's +/// `contains` would compare grapheme clusters). +func jsIncludes(_ haystack: String, _ needle: String) -> Bool { + let h = Array(haystack.utf16) + let n = Array(needle.utf16) + if n.isEmpty { return true } + guard n.count <= h.count else { return false } + for start in 0...(h.count - n.count) where h[start] == n[0] { + if Array(h[start.. OpenUIValue { + if path.isEmpty || value.isNullish { return .undefined } + if !path.contains(".") { return jsProperty(value, path) } + var current = value + for part in path.split(separator: ".", omittingEmptySubsequences: false) { + if current.isNullish { return .undefined } + current = jsProperty(current, String(part)) + } + return current +} + +/// `Math.min` / `Math.max` semantics: NaN propagates, -0 < +0. +private func jsMin(_ a: Double, _ b: Double) -> Double { + if a.isNaN || b.isNaN { return .nan } + if a == 0 && b == 0 { return a.sign == .minus ? a : b } + return a < b ? a : b +} + +private func jsMax(_ a: Double, _ b: Double) -> Double { + if a.isNaN || b.isNaN { return .nan } + if a == 0 && b == 0 { return a.sign == .plus ? a : b } + return a > b ? a : b +} + +/// `Math.round`: halves round toward +∞. +func jsRound(_ value: Double) -> Double { + if !value.isFinite { return value } + let floored = value.rounded(.down) + let result = value - floored >= 0.5 ? floored + 1 : floored + return result == 0 && value < 0 ? -0.0 : result +} + +/// `String.prototype.localeCompare` with the default locale. +private func jsLocaleCompare(_ a: String, _ b: String) -> Double { + switch a.compare(b, options: [], range: nil, locale: Locale(identifier: "en")) { + case .orderedAscending: return -1 + case .orderedDescending: return 1 + case .orderedSame: return 0 + } +} + +/// `Array.prototype.sort` with a comparator: stable, `undefined` items last, +/// a NaN comparator result counts as equal. +private func jsSort(_ items: [OpenUIValue], _ compare: (OpenUIValue, OpenUIValue) -> Double) + -> [OpenUIValue] +{ + let defined = items.enumerated().filter { $0.element != .undefined } + let undefinedCount = items.count - defined.count + let sorted = defined.sorted { lhs, rhs in + let result = compare(lhs.element, rhs.element) + if result < 0 { return true } + if result > 0 { return false } + return lhs.offset < rhs.offset + } + return sorted.map(\.element) + Array(repeating: .undefined, count: undefinedCount) +} + +private func isNumericForSort(_ value: OpenUIValue) -> Bool { + switch value { + case .number: return true + case .string(let string): return !string.isEmpty && !jsStringToNumber(string).isNaN + default: return false + } +} + +/// Data builtins, keyed by name. Mirrors lang-core's `BUILTINS`. +public let builtins: [String: BuiltinDef] = { + let defs: [BuiltinDef] = [ + BuiltinDef( + name: "Count", signature: "Count(array) → number", description: "Returns array length" + ) { args in + if case .array(let items) = arg(args, 0) { return .number(Double(items.count)) } + return .number(0) + }, + BuiltinDef( + name: "First", signature: "First(array) → element", + description: "Returns first element of array" + ) { args in + guard case .array(let items) = arg(args, 0), let first = items.first, !first.isNullish + else { return .null } + return first + }, + BuiltinDef( + name: "Last", signature: "Last(array) → element", description: "Returns last element of array" + ) { args in + guard case .array(let items) = arg(args, 0), let last = items.last, !last.isNullish + else { return .null } + return last + }, + BuiltinDef( + name: "Sum", signature: "Sum(numbers[]) → number", description: "Sum of numeric array" + ) { args in + guard case .array(let items) = arg(args, 0) else { return .number(0) } + return .number(items.reduce(0) { $0 + toNumber($1) }) + }, + BuiltinDef( + name: "Avg", signature: "Avg(numbers[]) → number", description: "Average of numeric array" + ) { args in + guard case .array(let items) = arg(args, 0), !items.isEmpty else { return .number(0) } + return .number(items.reduce(0) { $0 + toNumber($1) } / Double(items.count)) + }, + BuiltinDef( + name: "Min", signature: "Min(numbers[]) → number", description: "Minimum value in array" + ) { args in + guard case .array(let items) = arg(args, 0), let first = items.first else { + return .number(0) + } + return .number(items.reduce(toNumber(first)) { jsMin($0, toNumber($1)) }) + }, + BuiltinDef( + name: "Max", signature: "Max(numbers[]) → number", description: "Maximum value in array" + ) { args in + guard case .array(let items) = arg(args, 0), let first = items.first else { + return .number(0) + } + return .number(items.reduce(toNumber(first)) { jsMax($0, toNumber($1)) }) + }, + BuiltinDef( + name: "Sort", signature: "Sort(array, field, direction?) → sorted array", + description: "Sort array by field. Direction: \"asc\" (default) or \"desc\"" + ) { args in + guard case .array(let items) = arg(args, 0) else { return arg(args, 0) } + let field = stringOrEmpty(arg(args, 1)) + let descending = (arg(args, 2).isNullish ? "asc" : arg(args, 2).jsString) == "desc" + return .array( + jsSort(items) { a, b in + let av = field.isEmpty ? a : resolveField(a, field) + let bv = field.isEmpty ? b : resolveField(b, field) + if isNumericForSort(av) && isNumericForSort(bv) { + let diff = toNumber(av) - toNumber(bv) + return descending ? -diff : diff + } + let cmp = jsLocaleCompare(stringOrEmpty(av), stringOrEmpty(bv)) + return descending ? -cmp : cmp + }) + }, + BuiltinDef( + name: "Filter", + signature: + "Filter(array, field, operator: \"==\" | \"!=\" | \">\" | \"<\" | \">=\" | \"<=\" | \"contains\", value) → filtered array", + description: "Filter array by field value" + ) { args in + guard case .array(let items) = arg(args, 0) else { return .array([]) } + let field = stringOrEmpty(arg(args, 1)) + let op = arg(args, 2).isNullish ? "==" : arg(args, 2).jsString + let value = arg(args, 3) + return .array( + items.filter { item in + let v = field.isEmpty ? item : resolveField(item, field) + switch op { + case "==": return v.looselyEquals(value) + case "!=": return !v.looselyEquals(value) + case ">": return toNumber(v) > toNumber(value) + case "<": return toNumber(v) < toNumber(value) + case ">=": return toNumber(v) >= toNumber(value) + case "<=": return toNumber(v) <= toNumber(value) + case "contains": return jsIncludes(stringOrEmpty(v), stringOrEmpty(value)) + default: return false + } + }) + }, + BuiltinDef( + name: "Round", signature: "Round(number, decimals?) → number", + description: "Round to N decimal places (default 0)" + ) { args in + let number = toNumber(arg(args, 0)) + let decimals = arg(args, 1).isNullish ? 0 : toNumber(arg(args, 1)) + let factor = pow(10, decimals) + return .number(jsRound(number * factor) / factor) + }, + BuiltinDef(name: "Abs", signature: "Abs(number) → number", description: "Absolute value") { + args in .number(abs(toNumber(arg(args, 0)))) + }, + BuiltinDef( + name: "Floor", signature: "Floor(number) → number", + description: "Round down to nearest integer" + ) { args in .number(toNumber(arg(args, 0)).rounded(.down)) }, + BuiltinDef( + name: "Ceil", signature: "Ceil(number) → number", description: "Round up to nearest integer" + ) { args in .number(toNumber(arg(args, 0)).rounded(.up)) }, + ] + return Dictionary(uniqueKeysWithValues: defs.map { ($0.name, $0) }) +}() + +/// Builtin names in declaration order, for prompt docs. +public let builtinOrder = [ + "Count", "First", "Last", "Sum", "Avg", "Min", "Max", "Sort", "Filter", "Round", "Abs", "Floor", + "Ceil", +] + +/// Builtins that receive AST nodes instead of evaluated values. +public let lazyBuiltins: Set = ["Each"] + +public let lazyBuiltinDefs: [String: (signature: String, description: String)] = [ + "Each": ( + "Each(array, varName, template)", + "Evaluate template for each element. varName is the loop variable — use it ONLY inside the template expression (inline). Do NOT create a separate statement for the template." + ) +] + +/// Parser-level action step names mapped to runtime step types. +public let actionSteps: [String: String] = [ + "Run": "run", + "ToAssistant": "continue_conversation", + "OpenUrl": "open_url", + "Set": "set", + "Reset": "reset", +] + +/// Action step names plus the `Action` container. +public let actionNames: Set = Set(["Action"]).union(actionSteps.keys) + +/// Every builtin name, including action expressions. +public let builtinNames: Set = Set(builtins.keys).union(lazyBuiltins).union(actionNames) + +public func isBuiltin(_ name: String) -> Bool { builtinNames.contains(name) } + +/// Statement-level calls that are neither builtins nor components. +public enum ReservedCall { + public static let query = "Query" + public static let mutation = "Mutation" +} + +public func isReservedCall(_ name: String) -> Bool { + name == ReservedCall.query || name == ReservedCall.mutation +} diff --git a/packages/swift-lang/Sources/OpenUILang/Expressions.swift b/packages/swift-lang/Sources/OpenUILang/Expressions.swift new file mode 100644 index 0000000000..80e3f15e13 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Expressions.swift @@ -0,0 +1,224 @@ +// Precedence levels (spec section 2.11). +private let precTernary = 1 +private let precOr = 2 +private let precAnd = 3 +private let precEq = 4 +private let precCmp = 5 +private let precAdd = 6 +private let precMul = 7 +private let precUnary = 8 +private let precMember = 9 + +/// `name.replace(/^\$/, "")` +private func dropDollar(_ name: String) -> String { + name.hasPrefix("$") ? String(name.dropFirst()) : name +} + +/// Parses a statement's tokens into an AST with a Pratt (top-down operator +/// precedence) parser. Malformed input never throws: unknown tokens become +/// `Null` and missing closers are tolerated. +public func parseExpression(_ tokens: [Token]) -> ASTNode { + var parser = ExpressionParser(tokens: tokens) + return parser.parseExpr(0) +} + +private struct ExpressionParser { + let tokens: [Token] + var pos = 0 + + var cur: Token { pos < tokens.count ? tokens[pos] : Token(.eof) } + + @discardableResult + mutating func adv() -> Token { + let token = cur + pos += 1 + return token + } + + mutating func eat(_ type: TokenType) { + if cur.type == type { pos += 1 } + } + + func peekType(_ offset: Int) -> TokenType? { + pos + offset < tokens.count ? tokens[pos + offset].type : nil + } + + func infixPrecedence(_ token: Token) -> Int { + switch token.type { + case .question: return precTernary + case .or: return precOr + case .and: return precAnd + case .eqEq, .notEq: return precEq + case .greater, .less, .greaterEq, .lessEq: return precCmp + case .plus, .minus: return precAdd + case .star, .slash, .percent: return precMul + case .dot, .lBrack: return precMember + default: return 0 + } + } + + mutating func parseExpr(_ minPrec: Int) -> ASTNode { + var left = parsePrefix() + while infixPrecedence(cur) > minPrec { + left = parseInfix(left) + } + return left + } + + mutating func parsePrefix() -> ASTNode { + let token = cur + switch token.type { + case .str: + adv() + return .str(token.string ?? "") + case .num: + adv() + return .num(token.number ?? .nan) + case .true: + adv() + return .bool(true) + case .false: + adv() + return .bool(false) + case .null: + adv() + return .null + case .lBrack: + return parseArr() + case .lBrace: + return parseObj() + case .stateVar: + // `$var = expr` is an assignment (single `=`, not `==`). + let name = token.string ?? "" + adv() + if cur.type == .equals { + adv() + return .assign(target: name, value: parseExpr(0)) + } + return .stateRef(name) + case .type: + // Builtins need the @ prefix to be called; only Action is exempt. + let name = token.string ?? "" + if peekType(1) == .lParen && (!isBuiltin(name) || name == "Action") { return parseComp() } + adv() + return .ref(name) + case .builtinCall: + if peekType(1) == .lParen { return parseComp() } + adv() + return .ref(token.string ?? "") + case .ident: + adv() + return .ref(token.string ?? "") + case .not: + adv() + return .unaryOp(op: "!", operand: parseExpr(precUnary)) + case .minus: + adv() + return .unaryOp(op: "-", operand: parseExpr(precUnary)) + case .lParen: + adv() + let inner = parseExpr(0) + eat(.rParen) + return inner + default: + // Unknown token: skip it. + adv() + return .null + } + } + + mutating func parseInfix(_ left: ASTNode) -> ASTNode { + let token = cur + func binary(_ op: String, _ prec: Int) -> ASTNode { + adv() + return .binOp(op: op, left: left, right: parseExpr(prec)) + } + switch token.type { + case .plus: return binary("+", precAdd) + case .minus: return binary("-", precAdd) + case .star: return binary("*", precMul) + case .slash: return binary("/", precMul) + case .percent: return binary("%", precMul) + case .eqEq: return binary("==", precEq) + case .notEq: return binary("!=", precEq) + case .greater: return binary(">", precCmp) + case .less: return binary("<", precCmp) + case .greaterEq: return binary(">=", precCmp) + case .lessEq: return binary("<=", precCmp) + case .and: return binary("&&", precAnd) + case .or: return binary("||", precOr) + case .question: + // Right-associative: both branches parse at the lowest precedence. + adv() + let then = parseExpr(0) + eat(.colon) + let otherwise = parseExpr(0) + return .ternary(cond: left, then: then, else: otherwise) + case .dot: + adv() + let fieldToken = cur + adv() + let field: String + switch fieldToken.type { + case .ident, .type, .str, .num: field = fieldToken.valueString + case .stateVar: field = dropDollar(fieldToken.string ?? "") + default: field = "?" + } + return .member(obj: left, field: field) + case .lBrack: + adv() + let index = parseExpr(0) + eat(.rBrack) + return .index(obj: left, index: index) + default: + return left + } + } + + /// `TypeName(arg1, arg2, ...)` + mutating func parseComp() -> ASTNode { + let name = cur.string ?? "" + adv() + eat(.lParen) + var args: [ASTNode] = [] + while cur.type != .rParen && cur.type != .eof { + args.append(parseExpr(0)) + if cur.type == .comma { adv() } + } + eat(.rParen) + return .comp(name: name, args: args, mappedProps: nil) + } + + /// `[elem1, elem2, ...]` + mutating func parseArr() -> ASTNode { + adv() + var elements: [ASTNode] = [] + while cur.type != .rBrack && cur.type != .eof { + elements.append(parseExpr(0)) + if cur.type == .comma { adv() } + } + eat(.rBrack) + return .arr(elements) + } + + /// `{ key: value, ... }` + mutating func parseObj() -> ASTNode { + adv() + var entries: [ASTEntry] = [] + while cur.type != .rBrace && cur.type != .eof { + let keyToken = cur + adv() + let key: String + switch keyToken.type { + case .ident, .str, .type, .num: key = keyToken.valueString + case .stateVar: key = dropDollar(keyToken.string ?? "") + default: key = "?" + } + eat(.colon) + entries.append(ASTEntry(key, parseExpr(0))) + if cur.type == .comma { adv() } + } + eat(.rBrace) + return .obj(entries) + } +} diff --git a/packages/swift-lang/Sources/OpenUILang/JSON.swift b/packages/swift-lang/Sources/OpenUILang/JSON.swift new file mode 100644 index 0000000000..df71432f34 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/JSON.swift @@ -0,0 +1,424 @@ +/// JSON reading and writing with JavaScript semantics. +/// +/// Reading preserves object key order, which matters because a library's JSON +/// Schema lists props in positional-argument order. Writing matches +/// `JSON.stringify`, so Swift output can be compared with lang-core's. +public enum JSON { + public struct SyntaxError: Error, CustomStringConvertible { + public var description: String + } + + /// `JSON.parse`. Objects keep JavaScript key order. + public static func parse(_ text: String) throws -> OpenUIValue { + var reader = Reader(units: Array(text.utf16)) + reader.skipWhitespace() + let value = try reader.readValue() + reader.skipWhitespace() + guard reader.index == reader.units.count else { + throw SyntaxError(description: "Unexpected trailing characters at \(reader.index)") + } + return value + } + + /// `JSON.stringify` without indentation. `undefined` object members are + /// omitted, `undefined` array items and non-finite numbers become `null`. + public static func stringify(_ value: OpenUIValue) -> String { + var out = "" + write(value.jsonRepresentation, into: &out) + return out + } + + private static func write(_ value: OpenUIValue, into out: inout String) { + switch value { + case .undefined, .null: + out += "null" + case .bool(let bool): + out += bool ? "true" : "false" + case .number(let number): + out += number.isFinite ? jsNumberToString(number) : "null" + case .string(let string): + writeString(string, into: &out) + case .array(let items): + out += "[" + for (offset, item) in items.enumerated() { + if offset > 0 { out += "," } + write(item, into: &out) + } + out += "]" + case .object(let object): + out += "{" + var first = true + for (key, member) in object where member != .undefined { + if !first { out += "," } + first = false + writeString(key, into: &out) + out += ":" + write(member, into: &out) + } + out += "}" + default: + write(value.jsonRepresentation, into: &out) + } + } + + private static func writeString(_ string: String, into out: inout String) { + out += "\"" + for scalar in string.unicodeScalars { + switch scalar { + case "\"": out += "\\\"" + case "\\": out += "\\\\" + case "\u{08}": out += "\\b" + case "\u{0C}": out += "\\f" + case "\n": out += "\\n" + case "\r": out += "\\r" + case "\t": out += "\\t" + default: + if scalar.value < 0x20 { + let hex = String(scalar.value, radix: 16) + out += "\\u" + String(repeating: "0", count: 4 - hex.count) + hex + } else { + out.unicodeScalars.append(scalar) + } + } + } + out += "\"" + } + + // MARK: Reader + + struct Reader { + let units: [UInt16] + var index = 0 + + mutating func skipWhitespace() { + while index < units.count, + units[index] == 0x20 || units[index] == 0x09 || units[index] == 0x0A + || units[index] == 0x0D + { + index += 1 + } + } + + mutating func readValue() throws -> OpenUIValue { + guard index < units.count else { throw SyntaxError(description: "Unexpected end of JSON") } + switch units[index] { + case UInt16(ascii: "{"): return try readObject() + case UInt16(ascii: "["): return try readArray() + case UInt16(ascii: "\""): return .string(try readString()) + case UInt16(ascii: "t"): return try readKeyword("true", .bool(true)) + case UInt16(ascii: "f"): return try readKeyword("false", .bool(false)) + case UInt16(ascii: "n"): return try readKeyword("null", .null) + default: return try readNumber() + } + } + + mutating func readKeyword(_ word: String, _ value: OpenUIValue) throws -> OpenUIValue { + let wordUnits = Array(word.utf16) + guard index + wordUnits.count <= units.count, + Array(units[index.. OpenUIValue { + let start = index + if index < units.count, units[index] == UInt16(ascii: "-") { index += 1 } + while index < units.count, + (UInt16(ascii: "0")...UInt16(ascii: "9")).contains(units[index]) + || units[index] == UInt16(ascii: ".") || units[index] == UInt16(ascii: "e") + || units[index] == UInt16(ascii: "E") || units[index] == UInt16(ascii: "+") + || units[index] == UInt16(ascii: "-") + { + index += 1 + } + let text = String(decoding: units[start.. String { + index += 1 // opening quote + let start = index + while index < units.count { + if units[index] == UInt16(ascii: "\\") { + index += 2 + } else if units[index] == UInt16(ascii: "\"") { + let body = Array(units[start.. OpenUIValue { + index += 1 + var items: [OpenUIValue] = [] + skipWhitespace() + if index < units.count, units[index] == UInt16(ascii: "]") { + index += 1 + return .array(items) + } + while true { + skipWhitespace() + items.append(try readValue()) + skipWhitespace() + guard index < units.count else { throw SyntaxError(description: "Unterminated array") } + if units[index] == UInt16(ascii: ",") { + index += 1 + } else if units[index] == UInt16(ascii: "]") { + index += 1 + return .array(items) + } else { + throw SyntaxError(description: "Expected , or ] at \(index)") + } + } + } + + mutating func readObject() throws -> OpenUIValue { + index += 1 + var object = OpenUIObject() + skipWhitespace() + if index < units.count, units[index] == UInt16(ascii: "}") { + index += 1 + return .object(object) + } + while true { + skipWhitespace() + guard index < units.count, units[index] == UInt16(ascii: "\"") else { + throw SyntaxError(description: "Expected key at \(index)") + } + let key = try readString() + skipWhitespace() + guard index < units.count, units[index] == UInt16(ascii: ":") else { + throw SyntaxError(description: "Expected : at \(index)") + } + index += 1 + skipWhitespace() + object[key] = try readValue() + skipWhitespace() + guard index < units.count else { throw SyntaxError(description: "Unterminated object") } + if units[index] == UInt16(ascii: ",") { + index += 1 + } else if units[index] == UInt16(ascii: "}") { + index += 1 + return .object(object) + } else { + throw SyntaxError(description: "Expected , or } at \(index)") + } + } + } + } +} + +/// Decodes the body of a JSON string literal (without the quotes), following +/// `JSON.parse`: returns `nil` for raw control characters and invalid escapes. +/// Lone surrogates, which JavaScript strings can hold but Swift strings cannot, +/// decode to U+FFFD. +func decodeJSONStringBody(_ body: [UInt16]) -> String? { + var out: [UInt16] = [] + out.reserveCapacity(body.count) + var i = 0 + while i < body.count { + let unit = body[i] + if unit < 0x20 { return nil } + if unit != UInt16(ascii: "\\") { + out.append(unit) + i += 1 + continue + } + guard i + 1 < body.count else { return nil } + let escaped = body[i + 1] + i += 2 + switch escaped { + case UInt16(ascii: "\""): out.append(UInt16(ascii: "\"")) + case UInt16(ascii: "\\"): out.append(UInt16(ascii: "\\")) + case UInt16(ascii: "/"): out.append(UInt16(ascii: "/")) + case UInt16(ascii: "b"): out.append(0x08) + case UInt16(ascii: "f"): out.append(0x0C) + case UInt16(ascii: "n"): out.append(0x0A) + case UInt16(ascii: "r"): out.append(0x0D) + case UInt16(ascii: "t"): out.append(0x09) + case UInt16(ascii: "u"): + guard i + 4 <= body.count, + let code = UInt16(String(decoding: body[i.. Bool { + switch (self, other) { + case (.undefined, .undefined), (.null, .null), (.undefined, .null), (.null, .undefined): + return true + case (.undefined, _), (.null, _), (_, .undefined), (_, .null): + return false + case (.number(let lhs), .number(let rhs)): return lhs == rhs + case (.string(let lhs), .string(let rhs)): return lhs == rhs + case (.bool(let lhs), .bool(let rhs)): return lhs == rhs + case (.number(let lhs), .string(let rhs)): return lhs == jsStringToNumber(rhs) + case (.string(let lhs), .number(let rhs)): return jsStringToNumber(lhs) == rhs + case (.bool(let lhs), _): return OpenUIValue.number(lhs ? 1 : 0).looselyEquals(other) + case (_, .bool(let rhs)): return looselyEquals(.number(rhs ? 1 : 0)) + default: + if isPrimitiveForEquality, !other.isPrimitiveForEquality { + return looselyEquals(.string(other.jsString)) + } + if !isPrimitiveForEquality, other.isPrimitiveForEquality { + return OpenUIValue.string(jsString).looselyEquals(other) + } + return false + } + } + + /// JavaScript `===` for the values the store compares (`Object.is` for numbers + /// aside from NaN, structural for composites since they have no identity here). + func isSameValue(_ other: OpenUIValue) -> Bool { + switch (self, other) { + case (.number(let lhs), .number(let rhs)): + if lhs.isNaN && rhs.isNaN { return true } + return lhs == rhs && lhs.sign == rhs.sign + default: + return self == other + } + } +} + +/// lang-core's lenient `toNumber`: numbers pass through, numeric strings parse +/// (anything else becomes 0), booleans become 1/0, everything else is 0. +public func toNumber(_ value: OpenUIValue) -> Double { + switch value { + case .number(let number): return number + case .string(let string): + let number = jsStringToNumber(string) + return number.isNaN ? 0 : number + case .bool(let bool): return bool ? 1 : 0 + default: return 0 + } +} + +// MARK: - Number → String (ECMAScript Number::toString) + +/// Formats a number exactly like JavaScript's `String(number)`. +public func jsNumberToString(_ value: Double) -> String { + if value.isNaN { return "NaN" } + if value == 0 { return "0" } + if value < 0 { return "-" + jsNumberToString(-value) } + if value.isInfinite { return "Infinity" } + + let (digits, n) = shortestDigits(value) + let k = digits.count + if k <= n && n <= 21 { + return digits + String(repeating: "0", count: n - k) + } + if 0 < n && n <= 21 { + let index = digits.index(digits.startIndex, offsetBy: n) + return digits[.. (String, Int) { + // Swift's description is the shortest representation that round-trips. + let description = "\(value)" + var mantissa = Substring(description) + var exponent = 0 + if let e = description.firstIndex(where: { $0 == "e" || $0 == "E" }) { + mantissa = description[.. 1 ? parts[1] : "" + var digits = Array(integerPart + fractionPart) + var point = integerPart.count + exponent + while digits.first == "0" { + digits.removeFirst() + point -= 1 + } + while digits.last == "0" { digits.removeLast() } + return (String(digits), point) +} + +// MARK: - String → Number (ECMAScript StringToNumber) + +private let jsWhitespace: Set = [ + "\u{0009}", "\u{000A}", "\u{000B}", "\u{000C}", "\u{000D}", "\u{0020}", "\u{00A0}", "\u{1680}", + "\u{2000}", "\u{2001}", "\u{2002}", "\u{2003}", "\u{2004}", "\u{2005}", "\u{2006}", "\u{2007}", + "\u{2008}", "\u{2009}", "\u{200A}", "\u{2028}", "\u{2029}", "\u{202F}", "\u{205F}", "\u{3000}", + "\u{FEFF}", +] + +/// JavaScript `String.prototype.trim()`. +func jsTrim(_ string: String) -> String { + let scalars = Array(string.unicodeScalars) + var start = 0 + var end = scalars.count + while start < end, jsWhitespace.contains(scalars[start]) { start += 1 } + while end > start, jsWhitespace.contains(scalars[end - 1]) { end -= 1 } + var view = String.UnicodeScalarView() + view.append(contentsOf: scalars[start.. String { + var scalars = Array(string.unicodeScalars) + while let last = scalars.last, jsWhitespace.contains(last) { scalars.removeLast() } + var view = String.UnicodeScalarView() + view.append(contentsOf: scalars) + return String(view) +} + +/// JavaScript `Number(string)`. +public func jsStringToNumber(_ string: String) -> Double { + let text = jsTrim(string) + if text.isEmpty { return 0 } + switch text { + case "Infinity", "+Infinity": return .infinity + case "-Infinity": return -.infinity + default: break + } + let chars = Array(text.utf8) + if chars.count > 2, chars[0] == UInt8(ascii: "0") { + let radix: Int? = + switch chars[1] { + case UInt8(ascii: "x"), UInt8(ascii: "X"): 16 + case UInt8(ascii: "o"), UInt8(ascii: "O"): 8 + case UInt8(ascii: "b"), UInt8(ascii: "B"): 2 + default: nil + } + if let radix { + var result = 0.0 + for char in chars[2...] { + guard let digit = Int(String(UnicodeScalar(char)), radix: radix) else { return .nan } + result = result * Double(radix) + Double(digit) + } + return result + } + } + guard isStrDecimalLiteral(chars) else { return .nan } + return Double(text) ?? .nan +} + +/// `[+-] (digits [. digits?] | . digits) [(e|E) [+-] digits]` +private func isStrDecimalLiteral(_ chars: [UInt8]) -> Bool { + var i = 0 + func isDigit(_ index: Int) -> Bool { + index < chars.count && chars[index] >= UInt8(ascii: "0") && chars[index] <= UInt8(ascii: "9") + } + if i < chars.count, chars[i] == UInt8(ascii: "+") || chars[i] == UInt8(ascii: "-") { i += 1 } + var sawDigits = false + while isDigit(i) { + i += 1 + sawDigits = true + } + if i < chars.count, chars[i] == UInt8(ascii: ".") { + i += 1 + while isDigit(i) { + i += 1 + sawDigits = true + } + } + guard sawDigits else { return false } + if i < chars.count, chars[i] == UInt8(ascii: "e") || chars[i] == UInt8(ascii: "E") { + i += 1 + if i < chars.count, chars[i] == UInt8(ascii: "+") || chars[i] == UInt8(ascii: "-") { i += 1 } + guard isDigit(i) else { return false } + while isDigit(i) { i += 1 } + } + return i == chars.count +} + +extension UInt16 { + /// A UTF-16 code unit for an ASCII scalar; JavaScript strings are UTF-16. + init(ascii scalar: Unicode.Scalar) { + self = UInt16(scalar.value) + } +} diff --git a/packages/swift-lang/Sources/OpenUILang/Lexer.swift b/packages/swift-lang/Sources/OpenUILang/Lexer.swift new file mode 100644 index 0000000000..a8ecf0d323 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Lexer.swift @@ -0,0 +1,314 @@ +/// Token types for OpenUI Lang (mirrors lang-core's `T` enum). +public enum TokenType: Sendable, Equatable { + case newline + case lParen, rParen, lBrack, rBrack, lBrace, rBrace + case comma, colon, equals + case `true`, `false`, null + case eof + /// Carries a string value. + case str + /// Carries a numeric value. + case num + /// Lowercase identifier: a reference. + case ident + /// PascalCase identifier: a component name or reference. + case type + /// `$identifier`: a reactive state reference. + case stateVar + case dot, plus, minus, star, slash, percent + case eqEq, notEq, greater, less, greaterEq, lessEq + case and, or, not, question + /// `@identifier`: a builtin call. + case builtinCall +} + +public struct Token: Sendable, Equatable { + public var type: TokenType + public var string: String? + public var number: Double? + + init(_ type: TokenType, string: String? = nil, number: Double? = nil) { + self.type = type + self.string = string + self.number = number + } + + /// `String(tok.v)` for identifier-like tokens used as keys. + var valueString: String { + if let string { return string } + if let number { return jsNumberToString(number) } + return "undefined" + } +} + +extension UInt16 { + fileprivate var isASCIIDigit: Bool { self >= 0x30 && self <= 0x39 } + fileprivate var isASCIILower: Bool { self >= 0x61 && self <= 0x7A } + fileprivate var isASCIIUpper: Bool { self >= 0x41 && self <= 0x5A } + fileprivate var isIdentifierStart: Bool { isASCIILower || isASCIIUpper || self == 0x5F } + fileprivate var isIdentifierPart: Bool { isIdentifierStart || isASCIIDigit } +} + +private func char(_ scalar: Unicode.Scalar) -> UInt16 { UInt16(scalar.value) } + +/// Tokenizes OpenUI Lang source into a flat token array ending with `.eof`. +/// +/// Works on UTF-16 code units, like the JavaScript lexer, so string slicing, +/// escapes and skipped characters (emoji outside strings) behave identically. +public func tokenize(_ source: String) -> [Token] { + let src = Array(source.utf16) + let n = src.count + var tokens: [Token] = [] + var i = 0 + + func push(_ type: TokenType) { tokens.append(Token(type)) } + + while i < n { + // Horizontal whitespace; newlines are significant. + while i < n && (src[i] == char(" ") || src[i] == char("\t") || src[i] == char("\r")) { i += 1 } + if i >= n { break } + + let c = src[i] + let next: UInt16? = i + 1 < n ? src[i + 1] : nil + + switch c { + case char("\n"): + push(.newline) + i += 1 + continue + case char("("): + push(.lParen) + i += 1 + continue + case char(")"): + push(.rParen) + i += 1 + continue + case char("["): + push(.lBrack) + i += 1 + continue + case char("]"): + push(.rBrack) + i += 1 + continue + case char("{"): + push(.lBrace) + i += 1 + continue + case char("}"): + push(.rBrace) + i += 1 + continue + case char(","): + push(.comma) + i += 1 + continue + case char(":"): + push(.colon) + i += 1 + continue + case char("="): + if next == char("=") { + push(.eqEq) + i += 2 + } else { + push(.equals) + i += 1 + } + continue + case char("!"): + if next == char("=") { + push(.notEq) + i += 2 + } else { + push(.not) + i += 1 + } + continue + case char(">"): + if next == char("=") { + push(.greaterEq) + i += 2 + } else { + push(.greater) + i += 1 + } + continue + case char("<"): + if next == char("=") { + push(.lessEq) + i += 2 + } else { + push(.less) + i += 1 + } + continue + case char("&"): + // A single `&` is accepted as `&&`. + push(.and) + i += next == char("&") ? 2 : 1 + continue + case char("|"): + // A single `|` is accepted as `||`. + push(.or) + i += next == char("|") ? 2 : 1 + continue + case char("."): + push(.dot) + i += 1 + continue + case char("?"): + push(.question) + i += 1 + continue + case char("+"): + push(.plus) + i += 1 + continue + case char("*"): + push(.star) + i += 1 + continue + case char("/"): + push(.slash) + i += 1 + continue + case char("%"): + push(.percent) + i += 1 + continue + case char("\""): + let start = i + i += 1 + var isClosed = false + while i < n { + if src[i] == char("\\") { + i += 2 + } else if src[i] == char("\"") { + i += 1 + isClosed = true + break + } else { + i += 1 + } + } + i = min(i, n) + let raw = Array(src[start.. Bool { + switch value { + case .ast, .reactiveAssign: return true + case .array(let items): return items.contains(where: containsDynamicValue) + case .element(let element): return element.props.values.contains(where: containsDynamicValue) + case .object(let object): return object.values.contains(where: containsDynamicValue) + case .actionPlan(let plan): + return plan.steps.contains { if case .set = $0 { true } else { false } } + case .actionStep(.set): return true + default: return false + } +} + +private enum RefResolution { + case unresolved + case runtimeRef(ASTNode) + case target(ASTNode) +} + +/// Shared ref handling: cycle and missing-symbol detection, and Query/Mutation +/// declarations becoming `RuntimeRef`s. +private func lookupRef(_ name: String, _ ctx: MaterializeContext) -> RefResolution { + if ctx.visited.contains(name) || ctx.syms[name] == nil { + ctx.unres.append(name) + return .unresolved + } + let target = ctx.syms[name]! + ctx.markReached(name) + if case .comp(let callee, _, _) = target, isReservedCall(callee) { + let refType: RuntimeRefType = callee == ReservedCall.mutation ? .mutation : .query + return .runtimeRef(.runtimeRef(name, refType: refType)) + } + return .target(target) +} + +private func withStatement(_ name: String, _ ctx: MaterializeContext, _ body: () -> T) -> T { + ctx.visited.insert(name) + let previous = ctx.currentStatementId + ctx.currentStatementId = name + defer { + ctx.currentStatementId = previous + ctx.visited.remove(name) + } + return body() +} + +private func resolveRefValue(_ name: String, _ ctx: MaterializeContext) -> OpenUIValue { + switch lookupRef(name, ctx) { + case .unresolved: return .null + case .runtimeRef(let node): return .ast(node) + case .target(let target): + return withStatement(name, ctx) { + var result = materializeValue(target, ctx) + if case .element(var element) = result { + element.statementId = name + result = .element(element) + } + return result + } + } +} + +private func resolveRefExpr(_ name: String, _ ctx: MaterializeContext) -> ASTNode { + switch lookupRef(name, ctx) { + case .unresolved: return .ph(name) + case .runtimeRef(let node): return node + case .target(let target): return withStatement(name, ctx) { materializeExpr(target, ctx) } + } +} + +/// For a lazy builtin such as `Each(arr, varName, template)`, scopes the loop +/// variable so template refs to it are left alone. `nil` when not applicable. +private func materializeLazyBuiltin( + _ name: String, _ args: [ASTNode], _ mappedProps: [ASTEntry]?, _ ctx: MaterializeContext, + _ scopedRefs: Set +) -> ASTNode? { + guard lazyBuiltins.contains(name), args.count >= 3 else { return nil } + let varName: String + switch args[1] { + case .ref(let n): varName = n + case .str(let v): varName = v + default: return nil + } + var nextScoped = scopedRefs + nextScoped.insert(varName) + let recursed = args.enumerated().map { index, arg in + index == 1 ? arg : materializeExprInternal(arg, ctx, nextScoped) + } + return .comp(name: name, args: recursed, mappedProps: mappedProps) +} + +private func materializeExprInternal( + _ node: ASTNode, _ ctx: MaterializeContext, _ scopedRefs: Set +) -> ASTNode { + switch node { + case .ref(let name): + return scopedRefs.contains(name) ? node : resolveRefExpr(name, ctx) + case .ph: + return node + case .comp(let name, let args, let mappedProps): + if let lazy = materializeLazyBuiltin(name, args, mappedProps, ctx, scopedRefs) { return lazy } + let recursed = args.map { materializeExprInternal($0, ctx, scopedRefs) } + if isBuiltin(name) || isReservedCall(name) { + return .comp(name: name, args: recursed, mappedProps: mappedProps) + } + if let params = ctx.cat?[name] { + // Catalog component: mapped props let the evaluator build an element. + let mapped = zip(params, recursed).map { ASTEntry($0.name, $1) } + return .comp(name: name, args: recursed, mappedProps: mapped) + } + pushValidationIssue(ctx, name, "", .unknownComponent(available: ctx.cat?.componentNames)) + return .comp(name: name, args: recursed, mappedProps: mappedProps) + case .arr(let elements): + return .arr(elements.map { materializeExprInternal($0, ctx, scopedRefs) }) + case .obj(let entries): + return .obj( + entries.map { ASTEntry($0.key, materializeExprInternal($0.value, ctx, scopedRefs)) }) + case .binOp(let op, let left, let right): + return .binOp( + op: op, left: materializeExprInternal(left, ctx, scopedRefs), + right: materializeExprInternal(right, ctx, scopedRefs)) + case .unaryOp(let op, let operand): + return .unaryOp(op: op, operand: materializeExprInternal(operand, ctx, scopedRefs)) + case .ternary(let cond, let then, let otherwise): + return .ternary( + cond: materializeExprInternal(cond, ctx, scopedRefs), + then: materializeExprInternal(then, ctx, scopedRefs), + else: materializeExprInternal(otherwise, ctx, scopedRefs)) + case .member(let obj, let field): + return .member(obj: materializeExprInternal(obj, ctx, scopedRefs), field: field) + case .index(let obj, let index): + return .index( + obj: materializeExprInternal(obj, ctx, scopedRefs), + index: materializeExprInternal(index, ctx, scopedRefs)) + case .assign(let target, let value): + return .assign(target: target, value: materializeExprInternal(value, ctx, scopedRefs)) + default: + // Literals, StateRef and RuntimeRef pass through unchanged. + return node + } +} + +/// Normalizes an AST node for use inside a runtime expression: resolves refs and +/// adds `mappedProps` to catalog components. The structure stays AST. +func materializeExpr(_ node: ASTNode, _ ctx: MaterializeContext) -> ASTNode { + materializeExprInternal(node, ctx, []) +} + +/// Schema-aware lowering in one pass: resolves refs, maps positional arguments +/// to named props, validates required props, applies defaults, turns literals +/// into plain values and keeps runtime expressions as AST. +/// +/// Returns an element for catalog components, AST for builtins and runtime +/// expressions, plain values for literals and collections, and `null` for +/// placeholders and dropped components. +func materializeValue(_ node: ASTNode, _ ctx: MaterializeContext) -> OpenUIValue { + switch node { + case .ref(let name): + return resolveRefValue(name, ctx) + case .str(let value): + return .string(value) + case .num(let value): + return .number(value) + case .bool(let value): + return .bool(value) + case .null, .ph: + return .null + case .arr(let elements): + var items: [OpenUIValue] = [] + for element in elements { + // Unresolved placeholders are dropped from arrays, and so are components + // or refs that resolved to null (incomplete, unresolved or unknown). + if case .ph = element { continue } + let value = materializeValue(element, ctx) + if value == .null { + switch element { + case .comp, .ref: continue + default: break + } + } + items.append(value) + } + return .array(items) + case .obj(let entries): + var object = OpenUIObject() + for entry in entries { object[entry.key] = materializeValue(entry.value, ctx) } + return .object(object) + case .comp(let name, let args, let mappedProps): + return materializeComponent(name, args, mappedProps, ctx) + default: + return node.isRuntimeExpr ? .ast(materializeExpr(node, ctx)) : .ast(node) + } +} + +private func materializeComponent( + _ name: String, _ args: [ASTNode], _ mappedProps: [ASTEntry]?, _ ctx: MaterializeContext +) -> OpenUIValue { + // Builtins (Sum, Count, Action, ...) stay AST for the runtime. + if isBuiltin(name) { + if let lazy = materializeLazyBuiltin(name, args, mappedProps, ctx, []) { return .ast(lazy) } + return .ast( + .comp(name: name, args: args.map { materializeExpr($0, ctx) }, mappedProps: mappedProps)) + } + // Query/Mutation are only valid as top-level statements. + if isReservedCall(name) { + pushValidationIssue(ctx, name, "", .inlineReserved) + return .null + } + guard let params = ctx.cat?[name] else { + pushValidationIssue(ctx, name, "", .unknownComponent(available: ctx.cat?.componentNames)) + return .null + } + + var props = OpenUIObject() + // Set when a required prop holds invalid data with no default to fall back on. + var dropComponent = false + for (param, arg) in zip(params, args) { + var value = materializeValue(arg, ctx) + let invalid = + param.schema != nil + && validateSchemaValue(&value, param.schema, name, "/\(param.name)", ctx) + props[param.name] = value + if invalid, + resolveInvalidValue( + &props, param.name, required: param.required, defaultValue: param.defaultValue) + { + dropComponent = true + } + } + + // Extra positional arguments are dropped. + if args.count > params.count { + pushValidationIssue(ctx, name, "", .excessArgs(declared: params.count, got: args.count)) + } + + // Required props: fall back to the schema default before dropping the component. + let missingRequired = params.filter { param in + param.required && (!props.contains(param.name) || props[param.name] == .null) + } + if !missingRequired.isEmpty { + let stillInvalid = missingRequired.filter { param in + if let defaultValue = param.defaultValue { + props[param.name] = defaultValue + return false + } + return true + } + if !stillInvalid.isEmpty { + let signature = buildParamsSignature(name, params) + for param in stillInvalid { + pushValidationIssue( + ctx, name, "/\(param.name)", + props.contains(param.name) + ? .nullRequired(signature: signature) : .missingRequired(signature: signature)) + } + return .null + } + } + + if dropComponent { return .null } + + let hasDynamicProps = props.values.contains(where: containsDynamicValue) + return .element( + ElementNode( + typeName: name, props: props, partial: ctx.partial, hasDynamicProps: hasDynamicProps)) +} diff --git a/packages/swift-lang/Sources/OpenUILang/Parser.swift b/packages/swift-lang/Sources/OpenUILang/Parser.swift new file mode 100644 index 0000000000..48a72b9432 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Parser.swift @@ -0,0 +1,543 @@ +/// An insertion-ordered statement map with JavaScript `Map` semantics: +/// re-setting a key replaces the value but keeps its original position. +struct StatementMap { + private(set) var order: [String] = [] + private var storage: [String: Statement] = [:] + + var count: Int { order.count } + var values: [Statement] { order.map { storage[$0]! } } + + subscript(id: String) -> Statement? { storage[id] } + + func contains(_ id: String) -> Bool { storage[id] != nil } + + mutating func set(_ statement: Statement) { + if storage.updateValue(statement, forKey: statement.id) == nil { order.append(statement.id) } + } + + mutating func removeAll() { + order.removeAll() + storage.removeAll() + } +} + +// MARK: - Statement classification + +/// The `$variable` names referenced anywhere in a node, in first-seen order. +func collectQueryDeps(_ node: ASTNode?) -> [String] { + guard let node else { return [] } + var refs: [String] = [] + var seen: Set = [] + node.walk { current in + if case .stateRef(let name) = current, seen.insert(name).inserted { refs.append(name) } + } + return refs +} + +private func classifyStatement(_ raw: RawStatement, _ expr: ASTNode) -> Statement { + // Query is checked before $var so `$foo = Query(...)` is still a query. + if case .comp(let name, let args, _) = expr, name == ReservedCall.query { + let deps = collectQueryDeps(args.count > 1 ? args[1] : nil) + return .query( + id: raw.id, call: CallNode(callee: ReservedCall.query, args: args), expr: expr, + deps: deps.isEmpty ? nil : deps) + } + if case .comp(let name, let args, _) = expr, name == ReservedCall.mutation { + return .mutation( + id: raw.id, call: CallNode(callee: ReservedCall.mutation, args: args), expr: expr) + } + if raw.idTokenType == .stateVar { return .state(id: raw.id, initial: expr) } + return .value(id: raw.id, expr: expr) +} + +private func extractStatements(_ statements: [Statement], _ ctx: MaterializeContext) -> ( + OpenUIObject, [QueryStatementInfo], [MutationStatementInfo] +) { + var stateDeclarations = OpenUIObject() + var queries: [QueryStatementInfo] = [] + var mutations: [MutationStatementInfo] = [] + + for statement in statements { + switch statement { + case .state(let id, let initial): + stateDeclarations[id] = materializeValue(initial, ctx) + case .query(let id, let call, _, let deps): + let args = call.args + queries.append( + QueryStatementInfo( + statementId: id, toolAST: args.first, argsAST: args.count > 1 ? args[1] : nil, + defaultsAST: args.count > 2 ? args[2] : nil, refreshAST: args.count > 3 ? args[3] : nil, + deps: deps, complete: true)) + case .mutation(let id, let call, _): + let args = call.args + mutations.append( + MutationStatementInfo( + statementId: id, toolAST: args.first, argsAST: args.count > 1 ? args[1] : nil)) + case .value: + break + } + } + + // Any $var referenced but never declared defaults to null. + for statement in statements { + let nodes: [ASTNode] + switch statement { + case .state(_, let initial): nodes = [initial] + case .value(_, let expr): nodes = [expr] + case .query(_, let call, _, _), .mutation(_, let call, _): nodes = call.args + } + for node in nodes { + for dep in collectQueryDeps(node) where !stateDeclarations.contains(dep) { + stateDeclarations[dep] = .null + } + } + } + + return (stateDeclarations, queries, mutations) +} + +private let defaultRootStatementId = "root" + +private func isComponentStatement(_ statement: Statement) -> String? { + guard case .value(_, .comp(let name, _, _)) = statement, !isBuiltin(name), + name != ReservedCall.query, name != ReservedCall.mutation + else { return nil } + return name +} + +/// The entry statement: `root`, then a statement named after the library root, +/// then the first statement calling the root component, then the first +/// component statement, then the first statement. +private func pickEntryId( + _ map: StatementMap, _ statements: [Statement], _ firstId: String, _ rootName: String? +) -> String { + if map.contains(defaultRootStatementId) { return defaultRootStatementId } + if let rootName, map.contains(rootName) { return rootName } + if let rootName, + let preferred = statements.first(where: { isComponentStatement($0) == rootName }) + { + return preferred.id + } + return statements.first(where: { isComponentStatement($0) != nil })?.id ?? firstId +} + +private func buildResult( + _ map: StatementMap, _ statements: [Statement], _ firstId: String, _ wasIncomplete: Bool, + _ statementCount: Int, _ cat: ParamMap?, _ rootName: String? +) -> ParseResult { + let entryId = pickEntryId(map, statements, firstId, rootName) + guard map.contains(entryId) else { return .empty(incomplete: wasIncomplete) } + + var syms: [String: ASTNode] = [:] + var unreached: [String] = [] + for id in map.order { + let statement = map[id]! + switch statement { + case .state(_, let initial): + syms[id] = initial + case .value(_, let expr), .query(_, _, let expr, _), .mutation(_, _, let expr): + syms[id] = expr + } + // Orphan tracking covers value statements other than the entry; state, + // Query and Mutation declarations are consumed separately. + if id != entryId, case .value = statement { unreached.append(id) } + } + + let ctx = MaterializeContext( + syms: syms, cat: cat, partial: wasIncomplete, currentStatementId: entryId) + ctx.unreached = unreached + var root: ElementNode? = nil + if case .element(var element) = materializeValue(syms[entryId]!, ctx) { + element.statementId = entryId + root = element + } + + let (stateDeclarations, queries, mutations) = extractStatements(statements, ctx) + + return ParseResult( + root: root, + meta: .init( + incomplete: wasIncomplete, unresolved: ctx.unres, orphaned: ctx.unreached ?? [], + statementCount: statementCount, errors: ctx.errors), + stateDeclarations: stateDeclarations, queryStatements: queries, mutationStatements: mutations) +} + +// MARK: - Preprocessing + +private let quote = UInt16(ascii: "\"") +private let singleQuote = UInt16(ascii: "'") +private let backslash = UInt16(ascii: "\\") +private let backtick = UInt16(ascii: "`") +private let newline = UInt16(ascii: "\n") + +/// Index after a double-quoted string starting at `start`, or `start` if none starts there. +private func skipString(_ input: [UInt16], _ start: Int) -> Int { + guard start < input.count, input[start] == quote else { return start } + var i = start + 1 + while i < input.count { + if input[i] == backslash { + i += 2 + } else if input[i] == quote { + return i + 1 + } else { + i += 1 + } + } + return i +} + +private func isFence(_ input: [UInt16], _ i: Int) -> Bool { + i + 2 < input.count && input[i] == backtick && input[i + 1] == backtick + && input[i + 2] == backtick +} + +private func string(_ units: ArraySlice) -> String { + String(decoding: units, as: UTF16.self) +} + +/// Extracts code from markdown fences (joining multiple blocks), or returns the +/// input unchanged when there are none. Fences inside double-quoted strings are ignored. +public func stripFences(_ text: String) -> String { + let input = Array(text.utf16) + var blocks: [String] = [] + var i = 0 + + while i < input.count { + var fenceStart = -1 + while i < input.count { + let next = skipString(input, i) + if next > i { + i = next + continue + } + if isFence(input, i) { + fenceStart = i + break + } + i += 1 + } + if fenceStart == -1 { break } + + // Skip the language tag. + var j = fenceStart + 3 + while j < input.count && input[j] != newline { j += 1 } + if j >= input.count { + // No newline after the opening fence yet (streaming): the rest is the tag line. + blocks.append("") + i = input.count + break + } + j += 1 + + var closePos = -1 + var k = j + while k < input.count { + let next = skipString(input, k) + if next > k { + k = next + continue + } + if isFence(input, k) { + closePos = k + break + } + k += 1 + } + + if closePos != -1 { + blocks.append(string(input[j.. Int? { + guard units.count >= 3 else { return nil } + for i in stride(from: units.count - 3, through: 0, by: -1) where isFence(units, i) { return i } + return nil +} + +/// Strips `//` and `#` line comments outside strings. String state carries +/// across lines, as in lang-core. +private func stripComments(_ text: String) -> String { + var inString: UInt16? = nil + // Split on UTF-16 newlines like `split("\n")`; Swift treats "\r\n" as one Character. + let lines = Array(text.utf16).split(separator: newline, omittingEmptySubsequences: false) + return lines.map { line -> String in + let units = Array(line) + var i = 0 + while i < units.count { + let c = units[i] + if let quoteChar = inString { + if c == backslash && i + 1 < units.count { + i += 2 + continue + } + if c == quoteChar { inString = nil } + i += 1 + continue + } + if c == quote || c == singleQuote { + inString = c + i += 1 + continue + } + if c == UInt16(ascii: "/") && i + 1 < units.count && units[i + 1] == UInt16(ascii: "/") { + return jsTrimEnd(string(units[.. String { + jsTrim(stripComments(stripFences(jsTrim(input)))) +} + +// MARK: - Parsing + +/// Compiles positional parameter lists from a library JSON Schema +/// (`$defs` keyed by component name, properties in positional order). +public func compileSchema(_ schema: OpenUIValue) -> ParamMap { + var map = ParamMap() + guard let defs = schema["$defs"].objectValue else { return map } + for (name, def) in defs { + let properties = def["properties"].objectValue ?? OpenUIObject() + let required = (def["required"].arrayValue ?? []).compactMap(\.stringValue) + map[name] = properties.keys.map { key in + ParamDef( + name: key, required: required.contains(key), + defaultValue: schemaDefaultValue(properties[key]), schema: properties[key]) + } + } + return map +} + +/// Parses a complete (or partial) OpenUI Lang response in one pass. +public func parse(_ input: String, _ cat: ParamMap?, rootName: String? = nil) -> ParseResult { + let trimmed = preprocess(input) + if trimmed.isEmpty { return .empty() } + + let (text, wasIncomplete) = autoClose(trimmed) + let rawStatements = splitStatements(tokenize(text)) + if rawStatements.isEmpty { return .empty(incomplete: wasIncomplete) } + + var map = StatementMap() + var firstId = "" + for raw in rawStatements { + map.set(classifyStatement(raw, parseExpression(raw.tokens))) + if firstId.isEmpty { firstId = raw.id } + } + return buildResult(map, map.values, firstId, wasIncomplete, map.count, cat, rootName) +} + +/// A parser that keeps completed statements between calls, so each streamed +/// chunk only re-parses the statement still being written. +public final class StreamParser { + private let cat: ParamMap? + private let rootName: String? + + /// Raw accumulated input, kept for `set(_:)` diffing. + private var buffer: [UInt16] = [] + /// Preprocessed view of the buffer. Statement boundaries are scanned on this, + /// so markdown prose or fences before the program can't confuse them. + private var cleaned: [UInt16] = [] + /// How far into `cleaned` statements are complete. + private var completedEnd = 0 + private var completedMap = StatementMap() + private var completedCount = 0 + private var firstId = "" + + public init(_ cat: ParamMap?, rootName: String? = nil) { + self.cat = cat + self.rootName = rootName + } + + /// Feeds the next chunk and returns the latest result. + public func push(_ chunk: String) -> ParseResult { + buffer.append(contentsOf: chunk.utf16) + return currentResult() + } + + /// Sets the full text so far. Appended text is diffed against the buffer; + /// replaced text resets the parser. + public func set(_ fullText: String) -> ParseResult { + let units = Array(fullText.utf16) + if units.count < buffer.count || !units.starts(with: buffer) { reset() } + if units.count > buffer.count { buffer.append(contentsOf: units[buffer.count...]) } + return currentResult() + } + + /// The latest result without consuming new data. + public func result() -> ParseResult { currentResult() } + + private func reset() { + buffer = [] + cleaned = [] + completedEnd = 0 + completedMap.removeAll() + completedCount = 0 + firstId = "" + } + + private func addStatements(_ text: String) { + let trimmed = jsTrim(text) + if trimmed.isEmpty { return } + for raw in splitStatements(tokenize(trimmed)) { + completedMap.set(classifyStatement(raw, parseExpression(raw.tokens))) + completedCount += 1 + if firstId.isEmpty { firstId = raw.id } + } + } + + /// Recomputes `cleaned`. If the completed prefix moved (e.g. an opening fence + /// just appeared), the cache is stale and scanning restarts. + private func refreshCleaned() { + let next = Array(preprocess(String(decoding: buffer, as: UTF16.self)).utf16) + if !next.starts(with: cleaned.prefix(completedEnd)) { + completedEnd = 0 + completedMap.removeAll() + completedCount = 0 + firstId = "" + } + cleaned = next + } + + /// Moves completed statements into the cache; returns where the pending one starts. + private func scanNewCompleted() -> Int { + var depth = 0 + var ternaryDepth = 0 + var inString: UInt16? = nil + var escaped = false + var statementStart = completedEnd + + var i = completedEnd + while i < cleaned.count { + defer { i += 1 } + let c = cleaned[i] + if escaped { + escaped = false + continue + } + if c == backslash && inString != nil { + escaped = true + continue + } + if let quoteChar = inString { + if c == quoteChar { inString = nil } + continue + } + if c == quote || c == singleQuote { + inString = c + continue + } + switch c { + case UInt16(ascii: "("), UInt16(ascii: "["), UInt16(ascii: "{"): + depth += 1 + case UInt16(ascii: ")"), UInt16(ascii: "]"), UInt16(ascii: "}"): + depth = max(0, depth - 1) + case UInt16(ascii: "?") where depth == 0: + ternaryDepth += 1 + case UInt16(ascii: ":") where depth == 0 && ternaryDepth > 0: + ternaryDepth -= 1 + case newline where depth <= 0 && ternaryDepth <= 0: + // A following `?` (or `:` inside a ternary) continues the statement. + var peek = i + 1 + while peek < cleaned.count, + [UInt16(ascii: " "), UInt16(ascii: "\t"), UInt16(ascii: "\r"), newline].contains( + cleaned[peek]) + { + peek += 1 + } + if peek < cleaned.count, + cleaned[peek] == UInt16(ascii: "?") + || (cleaned[peek] == UInt16(ascii: ":") && ternaryDepth > 0) + { + continue + } + let text = jsTrim(string(cleaned[statementStart.. ParseResult { + refreshCleaned() + let pendingStart = scanNewCompleted() + let pendingText = jsTrim(string(cleaned[min(pendingStart, cleaned.count)...])) + + if pendingText.isEmpty { + if completedCount == 0 { return .empty() } + return buildResult( + completedMap, completedMap.values, firstId, false, completedCount, cat, rootName) + } + + // `cleaned` is already preprocessed; only the trailing statement needs closing. + let (closed, wasIncomplete) = autoClose(pendingText) + let rawStatements = splitStatements(tokenize(closed)) + + if rawStatements.isEmpty { + if completedCount == 0 { return .empty(incomplete: wasIncomplete) } + return buildResult( + completedMap, completedMap.values, firstId, wasIncomplete, completedCount, cat, rootName) + } + + // New ids render progressively; an existing id is only replaced once its + // pending expression no longer needs closing. + var allMap = completedMap + for raw in rawStatements { + if completedMap.contains(raw.id) && wasIncomplete { continue } + allMap.set(classifyStatement(raw, parseExpression(raw.tokens))) + } + let entryFallback = firstId.isEmpty ? rawStatements[0].id : firstId + return buildResult( + allMap, allMap.values, entryFallback, wasIncomplete, completedCount + rawStatements.count, + cat, rootName) + } +} + +/// A batch parser bound to a library's JSON Schema. +public struct Parser: Sendable { + public let paramMap: ParamMap + public let rootName: String? + + /// - Parameter schema: the library JSON Schema (`library.toJSONSchema()` in lang-core). + public init(schema: OpenUIValue, rootName: String? = nil) { + self.paramMap = compileSchema(schema) + self.rootName = rootName + } + + public func parse(_ input: String) -> ParseResult { + OpenUILang.parse(input, paramMap, rootName: rootName) + } + + public func makeStreamParser() -> StreamParser { + StreamParser(paramMap, rootName: rootName) + } +} diff --git a/packages/swift-lang/Sources/OpenUILang/Statements.swift b/packages/swift-lang/Sources/OpenUILang/Statements.swift new file mode 100644 index 0000000000..b3251200be --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Statements.swift @@ -0,0 +1,136 @@ +/// A raw `identifier = expression` statement before expression parsing. +struct RawStatement: Sendable { + var id: String + /// Token type of the identifier, used to classify the statement. + var idTokenType: TokenType + var tokens: [Token] +} + +/// Closes unterminated strings and brackets so partial, streaming input parses +/// without syntax errors. +public func autoClose(_ input: String) -> (text: String, wasIncomplete: Bool) { + var stack: [UInt16] = [] + var inString: UInt16? = nil + var escaped = false + + for c in input.utf16 { + if escaped { + escaped = false + continue + } + if c == UInt16(ascii: "\\") && inString != nil { + escaped = true + continue + } + if let quote = inString { + if c == quote { inString = nil } + continue + } + switch c { + case UInt16(ascii: "\""), UInt16(ascii: "'"): + inString = c + case UInt16(ascii: "("), UInt16(ascii: "["), UInt16(ascii: "{"): + stack.append(c) + case UInt16(ascii: ")"): + if stack.last == UInt16(ascii: "(") { stack.removeLast() } + case UInt16(ascii: "]"): + if stack.last == UInt16(ascii: "[") { stack.removeLast() } + case UInt16(ascii: "}"): + if stack.last == UInt16(ascii: "{") { stack.removeLast() } + default: + break + } + } + + let wasIncomplete = inString != nil || !stack.isEmpty + guard wasIncomplete else { return (input, false) } + + var out = input + if let quote = inString { + if escaped { out += "\\" } + out += String(decoding: [quote], as: UTF16.self) + } + for opener in stack.reversed() { + switch opener { + case UInt16(ascii: "("): out += ")" + case UInt16(ascii: "["): out += "]" + default: out += "}" + } + } + return (out, true) +} + +/// Splits the token stream into `identifier = expression` statements. +/// +/// Statements end at newlines at bracket depth 0. A newline followed by `?` +/// (or by `:` inside a ternary) continues a multi-line ternary. Lines without +/// an identifier and `=` are skipped. +func splitStatements(_ tokens: [Token]) -> [RawStatement] { + var statements: [RawStatement] = [] + var pos = 0 + + func skipLine() { + while pos < tokens.count && tokens[pos].type != .newline && tokens[pos].type != .eof { + pos += 1 + } + } + + while pos < tokens.count { + while pos < tokens.count && tokens[pos].type == .newline { pos += 1 } + if pos >= tokens.count || tokens[pos].type == .eof { break } + + let token = tokens[pos] + guard token.type == .ident || token.type == .type || token.type == .stateVar else { + skipLine() + continue + } + let id = token.string ?? "" + let idTokenType = token.type + pos += 1 + + guard pos < tokens.count, tokens[pos].type == .equals else { + skipLine() + continue + } + pos += 1 + + var expr: [Token] = [] + var depth = 0 + var ternaryDepth = 0 + while pos < tokens.count && tokens[pos].type != .eof { + let type = tokens[pos].type + if type == .newline && depth <= 0 && ternaryDepth <= 0 { + var peek = pos + 1 + while peek < tokens.count && tokens[peek].type == .newline { peek += 1 } + let nextType = peek < tokens.count ? tokens[peek].type : .eof + if nextType == .question || (nextType == .colon && ternaryDepth > 0) { + pos += 1 + continue + } + break + } + if type == .newline { + pos += 1 + continue + } + if type == .lParen || type == .lBrack || type == .lBrace { + depth += 1 + } else if (type == .rParen || type == .rBrack || type == .rBrace) && depth > 0 { + depth -= 1 + } else if type == .question && depth == 0 { + // Colons inside {} are object key separators, so only depth-0 `?`/`:` count. + ternaryDepth += 1 + } else if type == .colon && depth == 0 && ternaryDepth > 0 { + ternaryDepth -= 1 + } + expr.append(tokens[pos]) + pos += 1 + } + + if !expr.isEmpty { + statements.append(RawStatement(id: id, idTokenType: idTokenType, tokens: expr)) + } + } + + return statements +} diff --git a/packages/swift-lang/Sources/OpenUILang/Types.swift b/packages/swift-lang/Sources/OpenUILang/Types.swift new file mode 100644 index 0000000000..985502389a --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Types.swift @@ -0,0 +1,223 @@ +/// A resolved component node produced by the parser: positional arguments +/// mapped to named props through the library schema. +public struct ElementNode: Sendable, Equatable { + /// Source statement name (`header` in `header = TextContent(...)`); `nil` for inline components. + public var statementId: String? + /// Component name as defined in the library. + public var typeName: String + public var props: OpenUIObject + /// True while the parser hasn't received all tokens yet. + public var partial: Bool + /// False when every prop is a static literal, so evaluation can be skipped. + /// `nil` is treated as dynamic. + public var hasDynamicProps: Bool? + + public init( + statementId: String? = nil, typeName: String, props: OpenUIObject, partial: Bool, + hasDynamicProps: Bool? = nil + ) { + self.statementId = statementId + self.typeName = typeName + self.props = props + self.partial = partial + self.hasDynamicProps = hasDynamicProps + } +} + +public enum ValidationErrorCode: String, Sendable, Equatable { + case missingRequired = "missing-required" + case nullRequired = "null-required" + case unknownComponent = "unknown-component" + case inlineReserved = "inline-reserved" + case excessArgs = "excess-args" + case typeMismatch = "type-mismatch" +} + +/// A prop validation error. Components with missing required props are dropped +/// from the tree and reported here. +public struct ValidationError: Sendable, Equatable { + public var code: ValidationErrorCode + public var component: String + /// JSON Pointer within the props object, e.g. `/title`. + public var path: String + public var message: String + public var statementId: String? +} + +public enum OpenUIErrorSource: String, Sendable, Equatable { + case parser + case runtime + case query + case mutation +} + +/// A structured, LLM-friendly error from the OpenUI Lang pipeline. +public struct OpenUIError: Sendable, Equatable { + public var source: OpenUIErrorSource + /// A `ValidationErrorCode` raw value, or one of `runtime-error`, `render-error`, + /// `parse-exception`, `parse-failed`, `tool-not-found`, `tool-error`, `mcp-error`. + public var code: String + public var message: String + public var statementId: String? + public var component: String? + public var path: String? + public var toolName: String? + public var hint: String? + + public init( + source: OpenUIErrorSource, code: String, message: String, statementId: String? = nil, + component: String? = nil, path: String? = nil, toolName: String? = nil, hint: String? = nil + ) { + self.source = source + self.code = code + self.message = message + self.statementId = statementId + self.component = component + self.path = path + self.toolName = toolName + self.hint = hint + } +} + +/// Built-in action types delivered to the host app. +public enum BuiltinActionType { + public static let continueConversation = "continue_conversation" + public static let openUrl = "open_url" +} + +/// One step of an `ActionPlan`. Step type names match lang-core's `ACTION_STEPS`. +public enum ActionStep: Sendable, Equatable { + case run(statementId: String, refType: RuntimeRefType) + case continueConversation(message: String, context: String?) + case openUrl(url: String) + /// `valueAST` is evaluated when the action fires, not when it is built. + case set(target: String, valueAST: ASTNode) + case reset(targets: [String]) + + public var type: String { + switch self { + case .run: return "run" + case .continueConversation: return "continue_conversation" + case .openUrl: return "open_url" + case .set: return "set" + case .reset: return "reset" + } + } +} + +/// The ordered steps an `Action([...])` expression evaluates to. +public struct ActionPlan: Sendable, Equatable { + public var steps: [ActionStep] + + public init(steps: [ActionStep]) { + self.steps = steps + } +} + +/// A structured action event fired by interactive components. +public struct ActionEvent: Sendable, Equatable { + /// See `BuiltinActionType`; custom types pass through unchanged. + public var type: String + public var params: OpenUIObject + /// Human-readable label for the action (shown as the user message in chat). + public var humanFriendlyMessage: String + /// Form state at the time of the action. + public var formState: OpenUIObject? + public var formName: String? + + public init( + type: String, params: OpenUIObject = OpenUIObject(), humanFriendlyMessage: String, + formState: OpenUIObject? = nil, formName: String? = nil + ) { + self.type = type + self.params = params + self.humanFriendlyMessage = humanFriendlyMessage + self.formState = formState + self.formName = formName + } +} + +/// A two-way binding between a reactive prop and a `$state` variable. Setting +/// the field evaluates `expr` with `$value` bound to the new value. +public struct ReactiveAssign: Sendable, Equatable { + public var target: String + public var expr: ASTNode + + public init(target: String, expr: ASTNode) { + self.target = target + self.expr = expr + } +} + +/// A `Query(...)` statement with its positional arguments kept as AST. +public struct QueryStatementInfo: Sendable, Equatable { + public var statementId: String + public var toolAST: ASTNode? + public var argsAST: ASTNode? + public var defaultsAST: ASTNode? + public var refreshAST: ASTNode? + /// `$variable` dependencies of the arguments, collected at parse time. + public var deps: [String]? + public var complete: Bool +} + +/// A `Mutation(...)` statement with its positional arguments kept as AST. +public struct MutationStatementInfo: Sendable, Equatable { + public var statementId: String + public var toolAST: ASTNode? + public var argsAST: ASTNode? +} + +/// The result of parsing (or re-parsing while streaming) an OpenUI Lang response. +public struct ParseResult: Sendable, Equatable { + public struct Meta: Sendable, Equatable { + /// True if the input was truncated (still streaming). + public var incomplete: Bool + /// References used but not defined yet. + public var unresolved: [String] + /// Value statements defined but not reachable from the root. + public var orphaned: [String] + public var statementCount: Int + public var errors: [ValidationError] + } + + public var root: ElementNode? + public var meta: Meta + /// `$variable` declarations mapped to their default values. + public var stateDeclarations: OpenUIObject + public var queryStatements: [QueryStatementInfo] + public var mutationStatements: [MutationStatementInfo] + + static func empty(incomplete: Bool = true) -> ParseResult { + ParseResult( + root: nil, + meta: Meta( + incomplete: incomplete, unresolved: [], orphaned: [], statementCount: 0, errors: []), + stateDeclarations: OpenUIObject(), queryStatements: [], mutationStatements: []) + } +} + +/// A component parameter compiled from the library JSON Schema. +public struct ParamDef: Sendable, Equatable { + public var name: String + public var required: Bool + /// The schema `default`, used when a required prop is missing or null. + public var defaultValue: OpenUIValue? + public var schema: OpenUIValue? +} + +/// Positional parameter lists keyed by component name, in library order. +public struct ParamMap: Sendable, Equatable { + public var componentNames: [String] = [] + private var params: [String: [ParamDef]] = [:] + + public init() {} + + public subscript(component: String) -> [ParamDef]? { + get { params[component] } + set { + if params[component] == nil, newValue != nil { componentNames.append(component) } + params[component] = newValue + } + } +} diff --git a/packages/swift-lang/Sources/OpenUILang/Validation.swift b/packages/swift-lang/Sources/OpenUILang/Validation.swift new file mode 100644 index 0000000000..cba934b114 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Validation.swift @@ -0,0 +1,313 @@ +/// Mutable state threaded through one materialization pass. +final class MaterializeContext { + var syms: [String: ASTNode] + var cat: ParamMap? + var errors: [ValidationError] = [] + var unres: [String] = [] + var visited: Set = [] + var partial: Bool + /// The statement being materialized, for error attribution. + var currentStatementId: String? + /// Statements not reached yet, in insertion order. Whatever remains is orphaned. + var unreached: [String]? = nil + + init(syms: [String: ASTNode], cat: ParamMap?, partial: Bool, currentStatementId: String?) { + self.syms = syms + self.cat = cat + self.partial = partial + self.currentStatementId = currentStatementId + } + + func markReached(_ id: String) { + unreached?.removeAll { $0 == id } + } +} + +// MARK: - Schema introspection + +private let scalarTypeofs: Set = ["string", "number", "boolean"] + +private func isCompositeSchema(_ schema: OpenUIObject) -> Bool { + schema.contains("$ref") || schema.contains("anyOf") || schema.contains("oneOf") + || schema.contains("allOf") +} + +/// Scalar type or enum values of a JSON Schema leaf. +struct ScalarTypeInfo { + var expectedType: String? + var enumValues: [OpenUIValue]? +} + +func scalarTypeInfo(_ schema: OpenUIObject) -> ScalarTypeInfo { + if case .array(let values)? = schema["enum"] { return ScalarTypeInfo(enumValues: values) } + if let constant = schema["const"] { return ScalarTypeInfo(enumValues: [constant]) } + switch schema["type"] { + case .string("string"): return ScalarTypeInfo(expectedType: "string") + case .string("number"), .string("integer"): return ScalarTypeInfo(expectedType: "number") + case .string("boolean"): return ScalarTypeInfo(expectedType: "boolean") + default: return ScalarTypeInfo() + } +} + +/// A JSON Schema fragment's `default`; `nil` when it has none. +func schemaDefaultValue(_ property: OpenUIValue?) -> OpenUIValue? { + guard case .object(let object)? = property else { return nil } + return object["default"] +} + +/// The type hint used in signatures and messages, e.g. `string` or `"a"|"b"`. +func typeFromSchema(_ property: OpenUIValue?) -> String? { + guard case .object(let object)? = property else { return nil } + if case .string(let ref)? = object["$ref"] { + return ref.split(separator: "/", omittingEmptySubsequences: false).last.map(String.init) + } + let leaf = scalarTypeInfo(object) + if let enumValues = leaf.enumValues { + return enumValues.map { JSON.stringify($0) }.joined(separator: "|") + } + if let expectedType = leaf.expectedType { return expectedType } + if case .string(let type)? = object["type"] { return type } + return nil +} + +/// A typed signature like `Header(title*: string, variant: "a"|"b")`; `*` marks +/// required params, in positional order so an LLM can fix swapped arguments. +func buildParamsSignature(_ component: String, _ params: [ParamDef]) -> String { + let rendered = params.map { param -> String in + let marked = param.required ? "\(param.name)*" : param.name + if let type = typeFromSchema(param.schema) { return "\(marked): \(type)" } + return marked + } + return "\(component)(\(rendered.joined(separator: ", ")))" +} + +/// `Array.prototype.includes` (SameValueZero). +private func includes(_ values: [OpenUIValue], _ value: OpenUIValue) -> Bool { + values.contains { candidate in + if case .number(let a) = candidate, case .number(let b) = value { + return a == b || (a.isNaN && b.isNaN) + } + return candidate == value + } +} + +private func checkTypeMismatch(_ value: OpenUIValue, _ info: ScalarTypeInfo) -> ( + expected: String, actual: String +)? { + let actual = value.jsTypeof + if let enumValues = info.enumValues { + if !scalarTypeofs.contains(actual) { return nil } + if includes(enumValues, value) { return nil } + return ( + "one of [\(enumValues.map { JSON.stringify($0) }.joined(separator: ", "))]", + JSON.stringify(value) + ) + } + if let expectedType = info.expectedType, expectedType != actual { + return (expectedType, value.jsType) + } + return nil +} + +// MARK: - Errors + +enum ValidationIssue { + case typeMismatch(expected: String, actual: String) + case missingRequired(signature: String?) + case nullRequired(signature: String?) + case unknownComponent(available: [String]?) + case inlineReserved + case excessArgs(declared: Int, got: Int) + + var code: ValidationErrorCode { + switch self { + case .typeMismatch: return .typeMismatch + case .missingRequired: return .missingRequired + case .nullRequired: return .nullRequired + case .unknownComponent: return .unknownComponent + case .inlineReserved: return .inlineReserved + case .excessArgs: return .excessArgs + } + } +} + +private func validationMessage(_ component: String, _ path: String, _ issue: ValidationIssue) + -> String +{ + switch issue { + case .typeMismatch(let expected, let actual): + return "field \"\(path)\" expects \(expected) but got \(actual)" + case .missingRequired(let signature): + return "missing required field \"\(path)\"" + (signature.map { " — signature: \($0)" } ?? "") + case .nullRequired(let signature): + return "required field \"\(path)\" cannot be null" + + (signature.map { " — signature: \($0)" } ?? "") + case .unknownComponent(let available): + let list = + (available?.isEmpty == false) + ? ". Available components: \(available!.joined(separator: ", "))" : "" + return "Unknown component \"\(component)\" — not found in catalog or builtins\(list)" + case .inlineReserved: + return "\(component)() must be declared as a top-level statement, not used inline as a value" + case .excessArgs(let declared, let got): + return "\(component) takes \(declared) arg(s), got \(got) (\(got - declared) excess dropped)" + } +} + +func pushValidationIssue( + _ ctx: MaterializeContext, _ component: String, _ path: String, _ issue: ValidationIssue +) { + ctx.errors.append( + ValidationError( + code: issue.code, component: component, path: path, + message: validationMessage(component, path, issue), statementId: ctx.currentStatementId)) +} + +// MARK: - Invalid-value resolution (the edge rule) + +/// Substitutes a default for an invalid value when one exists. Otherwise a +/// required key propagates invalidity upward (returns true) and an optional +/// key is deleted. +func resolveInvalidValue( + _ container: inout OpenUIObject, _ key: String, required: Bool, defaultValue: OpenUIValue? +) -> Bool { + if let defaultValue { + container[key] = defaultValue + return false + } + if required { return true } + container[key] = nil + return false +} + +// MARK: - Validators + +/// Component elements in data slots: slots that admit components (`$ref`, +/// `anyOf`, `oneOf`) are unchecked, plain-data slots can never hold one. +private func validateElementPosition( + _ element: ElementNode, _ schema: OpenUIObject, _ component: String, _ path: String, + _ ctx: MaterializeContext +) -> Bool { + if isCompositeSchema(schema) { return false } + let type = schema["type"]?.stringValue + if type != nil || schema["enum"]?.arrayValue != nil || schema.contains("const") { + pushValidationIssue( + ctx, component, path, + .typeMismatch( + expected: type ?? "a literal value", actual: "component \"\(element.typeName)\"")) + return true + } + return false +} + +private func validateObjectValue( + _ value: inout OpenUIValue, _ schema: OpenUIObject, _ component: String, _ path: String, + _ ctx: MaterializeContext +) -> Bool { + guard case .object(var object) = value else { + pushValidationIssue( + ctx, component, path, .typeMismatch(expected: "object", actual: value.jsType)) + return true + } + let props = schema["properties"]?.objectValue ?? OpenUIObject() + let required: [String] = (schema["required"]?.arrayValue ?? []).compactMap(\.stringValue) + var invalid = false + // Structural checks are streaming-sensitive, so they only run on complete input. + if !ctx.partial { + for key in required { + let present = object.contains(key) + if !present || object[key]!.isNullish { + if let fallback = schemaDefaultValue(props[key]) { + object[key] = fallback + continue + } + pushValidationIssue( + ctx, component, "\(path)/\(key)", + present ? .nullRequired(signature: nil) : .missingRequired(signature: nil)) + invalid = true + } + } + } + for key in props.keys where object.contains(key) { + let sub = props[key] + var child = object[key]! + let childInvalid = validateSchemaValue(&child, sub, component, "\(path)/\(key)", ctx) + object[key] = child + if childInvalid, + resolveInvalidValue( + &object, key, required: required.contains(key), defaultValue: schemaDefaultValue(sub)) + { + invalid = true + } + } + value = .object(object) + return invalid +} + +/// Invalid items are pruned in place, after validating all of them so error +/// paths keep their original indices. +private func validateArrayValue( + _ value: inout OpenUIValue, _ schema: OpenUIObject, _ component: String, _ path: String, + _ ctx: MaterializeContext +) -> Bool { + guard case .array(var items) = value else { + pushValidationIssue( + ctx, component, path, .typeMismatch(expected: "array", actual: value.jsType)) + return true + } + guard case .object = schema["items"] else { return false } + let itemSchema = schema["items"] + var invalid: [Int] = [] + for index in items.indices { + if validateSchemaValue(&items[index], itemSchema, component, "\(path)/\(index)", ctx) { + invalid.append(index) + } + } + for index in invalid.reversed() { items.remove(at: index) } + value = .array(items) + return false +} + +/// Enum membership is deferred while streaming (a partial literal may still +/// complete to a valid member); scalar type checks always run. +private func validateLeafValue( + _ value: OpenUIValue, _ schema: OpenUIObject, _ component: String, _ path: String, + _ ctx: MaterializeContext +) -> Bool { + let leaf = scalarTypeInfo(schema) + if leaf.expectedType == nil && leaf.enumValues == nil { return false } + if leaf.enumValues != nil && ctx.partial { return false } + if let mismatch = checkTypeMismatch(value, leaf) { + pushValidationIssue( + ctx, component, path, .typeMismatch(expected: mismatch.expected, actual: mismatch.actual)) + return true + } + return false +} + +/// Validates a materialized value against a JSON Schema fragment, pruning +/// unsalvageable data along the way. Returns true when the value itself is +/// invalid; the caller then applies the edge rule (`resolveInvalidValue`). +func validateSchemaValue( + _ value: inout OpenUIValue, _ schema: OpenUIValue?, _ component: String, _ path: String, + _ ctx: MaterializeContext +) -> Bool { + guard case .object(let s)? = schema else { return false } + // Absence is handled by the parent's required checks. + if value.isNullish { return false } + switch value { + case .ast: + // Runtime expressions resolve later. + return false + case .element(let element): + return validateElementPosition(element, s, component, path, ctx) + default: + break + } + if isCompositeSchema(s) { return false } + switch s["type"] { + case .string("object"): return validateObjectValue(&value, s, component, path, ctx) + case .string("array"): return validateArrayValue(&value, s, component, path, ctx) + default: return validateLeafValue(value, s, component, path, ctx) + } +} diff --git a/packages/swift-lang/Sources/OpenUILang/Value.swift b/packages/swift-lang/Sources/OpenUILang/Value.swift new file mode 100644 index 0000000000..7493d4cfe2 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Value.swift @@ -0,0 +1,142 @@ +/// A dynamically typed value flowing through the parser and runtime. +/// +/// lang-core passes `unknown` values around and relies on JavaScript semantics +/// for them, so this enum keeps the distinctions those semantics depend on: +/// `undefined` versus `null`, and the parser/runtime markers (element nodes, +/// preserved AST expressions, action plans, reactive assignments) that live +/// inside props next to plain data. +public indirect enum OpenUIValue: Sendable, Equatable { + case undefined + case null + case bool(Bool) + case number(Double) + case string(String) + case array([OpenUIValue]) + case object(OpenUIObject) + case element(ElementNode) + case ast(ASTNode) + case actionPlan(ActionPlan) + case actionStep(ActionStep) + case reactiveAssign(ReactiveAssign) + + /// `null` or `undefined` (JavaScript's `value == null`). + public var isNullish: Bool { + switch self { + case .undefined, .null: return true + default: return false + } + } + + public var stringValue: String? { + if case .string(let value) = self { return value } + return nil + } + + public var numberValue: Double? { + if case .number(let value) = self { return value } + return nil + } + + public var boolValue: Bool? { + if case .bool(let value) = self { return value } + return nil + } + + public var arrayValue: [OpenUIValue]? { + if case .array(let value) = self { return value } + return nil + } + + public var objectValue: OpenUIObject? { + if case .object(let value) = self { return value } + return nil + } + + public var elementValue: ElementNode? { + if case .element(let value) = self { return value } + return nil + } + + /// Member lookup for plain objects; `undefined` for anything else. + public subscript(key: String) -> OpenUIValue { + if case .object(let object) = self { return object[key] ?? .undefined } + return .undefined + } +} + +extension OpenUIValue: ExpressibleByStringLiteral, ExpressibleByBooleanLiteral, + ExpressibleByFloatLiteral, ExpressibleByIntegerLiteral, ExpressibleByNilLiteral, + ExpressibleByArrayLiteral, ExpressibleByDictionaryLiteral +{ + public init(stringLiteral value: String) { self = .string(value) } + public init(booleanLiteral value: Bool) { self = .bool(value) } + public init(floatLiteral value: Double) { self = .number(value) } + public init(integerLiteral value: Int) { self = .number(Double(value)) } + public init(nilLiteral: ()) { self = .null } + public init(arrayLiteral elements: OpenUIValue...) { self = .array(elements) } + public init(dictionaryLiteral elements: (String, OpenUIValue)...) { + var object = OpenUIObject() + for (key, value) in elements { object[key] = value } + self = .object(object) + } +} + +/// An object with JavaScript property ordering. +/// +/// JavaScript enumerates integer-like keys first in ascending order, then the +/// remaining keys in insertion order. Prop order drives positional argument +/// mapping and error order, so the port keeps the same rule instead of using an +/// unordered dictionary. +public struct OpenUIObject: Sendable, Equatable, Sequence { + private var insertionOrder: [String] = [] + private var storage: [String: OpenUIValue] = [:] + + public init() {} + + public init(_ entries: [(String, OpenUIValue)]) { + for (key, value) in entries { self[key] = value } + } + + public var count: Int { storage.count } + public var isEmpty: Bool { storage.isEmpty } + + /// Keys in JavaScript enumeration order. + public var keys: [String] { + let indexKeys = insertionOrder.compactMap { key in arrayIndex(key).map { (key, $0) } } + guard !indexKeys.isEmpty else { return insertionOrder } + let sortedIndexKeys = indexKeys.sorted { $0.1 < $1.1 }.map(\.0) + return sortedIndexKeys + insertionOrder.filter { arrayIndex($0) == nil } + } + + public var values: [OpenUIValue] { keys.map { storage[$0]! } } + + public var entries: [(key: String, value: OpenUIValue)] { keys.map { ($0, storage[$0]!) } } + + public func contains(_ key: String) -> Bool { storage[key] != nil } + + /// Assigning `nil` deletes the key (JavaScript `delete`). + public subscript(key: String) -> OpenUIValue? { + get { storage[key] } + set { + if let newValue { + if storage.updateValue(newValue, forKey: key) == nil { insertionOrder.append(key) } + } else if storage.removeValue(forKey: key) != nil { + insertionOrder.removeAll { $0 == key } + } + } + } + + public func makeIterator() -> IndexingIterator<[(key: String, value: OpenUIValue)]> { + entries.makeIterator() + } + + public static func == (lhs: OpenUIObject, rhs: OpenUIObject) -> Bool { + lhs.keys == rhs.keys && lhs.storage == rhs.storage + } +} + +/// A canonical array index (`"0"` … `"4294967294"`), which JavaScript orders first. +private func arrayIndex(_ key: String) -> UInt32? { + guard let value = UInt32(key), value != UInt32.max, String(value) == key else { return nil } + return value +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Exports.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Exports.swift new file mode 100644 index 0000000000..2a8894f65b --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Exports.swift @@ -0,0 +1 @@ +@_exported import OpenUILang diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures.swift b/packages/swift-lang/Tests/OpenUILangTests/Fixtures.swift new file mode 100644 index 0000000000..c95291918b --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures.swift @@ -0,0 +1,67 @@ +import Foundation +import Testing + +@testable import OpenUILang + +/// Loads the conformance fixtures generated from @openuidev/lang-core +/// (see Scripts/generate-fixtures.mjs). +enum Fixtures { + static func load(_ name: String) -> OpenUIValue { + let url = Bundle.module.url(forResource: name, withExtension: "json", subdirectory: "Fixtures")! + let text = try! String(contentsOf: url, encoding: .utf8) + return try! JSON.parse(text) + } + + static let schemas = load("schemas") + + static func paramMap(_ schemaName: String) -> ParamMap { + compileSchema(schemas[schemaName]["schema"]) + } + + static func rootName(_ schemaName: String) -> String? { + schemas[schemaName]["root"].stringValue + } +} + +/// A named fixture case, printable in test output. +struct FixtureCase: CustomTestStringConvertible, Sendable { + let name: String + let value: OpenUIValue + var testDescription: String { name } + + static func all(_ file: String) -> [FixtureCase] { + (Fixtures.load(file).arrayValue ?? []).map { + FixtureCase(name: $0["name"].stringValue ?? "?", value: $0) + } + } +} + +/// Round-trips through JSON text so both sides get identical treatment of +/// `undefined`, NaN and -0, exactly as `JSON.stringify` would. +func normalized(_ value: OpenUIValue) -> OpenUIValue { + try! JSON.parse(JSON.stringify(value)) +} + +/// The path of the first difference between two JSON values, or nil if they +/// are equivalent. Object key order is ignored; array order is not. +func firstDifference(_ actual: OpenUIValue, _ expected: OpenUIValue, path: String = "$") -> String? +{ + switch (actual, expected) { + case (.object(let a), .object(let e)): + for key in Set(a.keys).union(e.keys).sorted() { + guard let av = a[key] else { return "\(path).\(key): missing in Swift result" } + guard let ev = e[key] else { return "\(path).\(key): unexpected in Swift result" } + if let diff = firstDifference(av, ev, path: "\(path).\(key)") { return diff } + } + return nil + case (.array(let a), .array(let e)): + if a.count != e.count { return "\(path): \(a.count) items, expected \(e.count)" } + for index in a.indices { + if let diff = firstDifference(a[index], e[index], path: "\(path)[\(index)]") { return diff } + } + return nil + default: + return actual == expected + ? nil : "\(path): got \(JSON.stringify(actual)), expected \(JSON.stringify(expected))" + } +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json new file mode 100644 index 0000000000..35cbb7bbe2 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json @@ -0,0 +1,5659 @@ +[ + { + "name": "chat-example-1", + "schema": "chat", + "input": "Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "CardHeader", + "props": { + "title": "Paris", + "subtitle": "The City of Light · France's Eternal Capital" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "header" + }, + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]." + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "intro" + }, + { + "type": "element", + "typeName": "ContextCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "ContextCardItem", + "props": { + "id": "art-museums", + "title": "Art & Museums", + "body": "143 museums including the Louvre & newly reopened Grand Palais.", + "bgColor": "gray", + "bgImageSrc": "https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "h1" + }, + { + "type": "element", + "typeName": "ContextCardItem", + "props": { + "id": "gastronomy", + "title": "Gastronomy", + "body": "9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.", + "bgColor": "gray" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "h2" + }, + { + "type": "element", + "typeName": "ContextCardItem", + "props": { + "id": "fashion-capital", + "title": "Fashion Capital", + "body": "Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.", + "bgColor": "gray", + "bgImageSrc": "https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "h3" + } + ], + "layout": "grid", + "responsive": true, + "action": { + "type": "continue_conversation", + "context": "Tell me more about this aspect of Paris" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "highlights" + }, + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "Paris by the Numbers", + "description": "Key visitor statistics" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "statsHeader" + }, + { + "type": "element", + "typeName": "OverviewCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "OverviewCardItem", + "props": { + "id": "annual-visitors", + "top": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "users", + "category": "people" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov1icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Annual Visitors", + "subtitle": "2024 arrivals", + "bold": false, + "layout": "vertical" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov1top" + }, + "bottom": { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "48.7M", + "subtext": "tourists", + "trend": { + "direction": "up", + "value": 2.5 + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov1metric" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov1" + }, + { + "type": "element", + "typeName": "OverviewCardItem", + "props": { + "id": "museums-monuments", + "top": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "landmark", + "category": "buildings" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov2icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Museums & Monuments", + "subtitle": "Cultural sites", + "bold": false, + "layout": "vertical" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov2top" + }, + "bottom": { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "2,370+", + "subtext": "across the city" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov2metric" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov2" + }, + { + "type": "element", + "typeName": "OverviewCardItem", + "props": { + "id": "tourism-revenue", + "top": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "circle-dollar-sign", + "category": "finance" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov3icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Tourism Revenue", + "subtitle": "2024 estimate", + "bold": false, + "layout": "vertical" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov3top" + }, + "bottom": { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "€23.4B", + "subtext": "generated" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov3metric" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov3" + } + ], + "layout": "grid", + "responsive": true + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "statsCards" + }, + { + "type": "element", + "typeName": "SectionBlock", + "props": { + "sections": [ + { + "type": "element", + "typeName": "SectionItem", + "props": { + "value": "landmarks", + "trigger": "Iconic Landmarks", + "content": [ + { + "type": "element", + "typeName": "VisualCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Eiffel Tower", + "subtext": "Open daily 9am–midnight", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm1body" + }, + "id": "eiffel-tower", + "bgImageSrc": "https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "Must-See", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "star", + "category": "shapes" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm1tagIcon" + }, + "size": "sm", + "variant": "info" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm1tag" + }, + "bgImageAlt": "Aerial view of the Eiffel Tower" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm1" + }, + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "The Louvre", + "subtext": "World's largest art museum", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm2body" + }, + "id": "the-louvre", + "bgImageSrc": "https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "8.9M visits/yr", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "trending-up", + "category": "charts" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm2tagIcon" + }, + "size": "sm", + "variant": "success" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm2tag" + }, + "bgImageAlt": "Exterior of the Louvre museum" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm2" + }, + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Notre-Dame", + "subtext": "Fully restored cathedral", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm3body" + }, + "id": "notre-dame", + "bgImageSrc": "https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "Reopened 2024", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "hammer", + "category": "tools" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm3tagIcon" + }, + "size": "sm", + "variant": "warning" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm3tag" + }, + "bgImageAlt": "Notre-Dame cathedral facade" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm3" + }, + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Palace of Versailles", + "subtext": "Royal gardens & grand halls", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm4body" + }, + "id": "versailles", + "bgImageSrc": "https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "Day Trip", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "train-front", + "category": "travel" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm4tagIcon" + }, + "size": "sm", + "variant": "neutral" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm4tag" + }, + "bgImageAlt": "Latona Fountain at Versailles" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm4" + } + ], + "layout": "carousel", + "responsive": true, + "action": { + "type": "continue_conversation", + "context": "Tell me more about this Paris landmark" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "landmarksCarousel" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "secLandmarks" + }, + { + "type": "element", + "typeName": "SectionItem", + "props": { + "value": "food", + "trigger": "Food & Drink", + "content": [ + { + "type": "element", + "typeName": "ContextCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "ContextCardItem", + "props": { + "id": "bistros", + "title": "Bistros", + "body": "Classic French fare — try Les Arlots for confit beef cheeks.", + "bgColor": "gray", + "bgImageSrc": "https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "f1" + }, + { + "type": "element", + "typeName": "ContextCardItem", + "props": { + "id": "fine-dining", + "title": "Fine Dining", + "body": "Septime leads a new wave of creative Michelin-starred cuisine.", + "bgColor": "gray", + "bgImageSrc": "https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "f2" + }, + { + "type": "element", + "typeName": "ContextCardItem", + "props": { + "id": "bakeries", + "title": "Bakeries", + "body": "Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.", + "bgColor": "gray", + "bgImageSrc": "https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "f3" + } + ], + "layout": "grid", + "responsive": true, + "action": { + "type": "continue_conversation", + "context": "Tell me more about eating and drinking in Paris" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "foodCards" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "secFood" + }, + { + "type": "element", + "typeName": "SectionItem", + "props": { + "value": "when", + "trigger": "Best Time to Visit", + "content": [ + { + "type": "element", + "typeName": "Tabs", + "props": { + "items": [ + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "spring", + "trigger": "Spring", + "content": [ + { + "type": "element", + "typeName": "ListBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "ListItem", + "props": { + "title": "Cherry blossoms at Parc de Sceaux", + "subtitle": "March – May", + "image": null, + "actionLabel": null, + "action": { + "type": "continue_conversation", + "context": "Tell me about cherry blossom season in Paris" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "sp1" + }, + { + "type": "element", + "typeName": "ListItem", + "props": { + "title": "Picnics along the Seine & in city parks", + "subtitle": "Warm, lively atmosphere", + "image": null, + "actionLabel": null, + "action": { + "type": "continue_conversation", + "context": "Where are the best picnic spots in Paris?" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "sp2" + }, + { + "type": "element", + "typeName": "ListItem", + "props": { + "title": "Fewer crowds than summer", + "subtitle": "Ideal for sightseeing", + "image": null, + "actionLabel": null, + "action": { + "type": "continue_conversation", + "context": "How busy is Paris in spring?" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "sp3" + } + ], + "variant": "number" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "springList" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabSpring" + }, + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "summer", + "trigger": "Summer", + "content": [ + { + "type": "element", + "typeName": "ListBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "ListItem", + "props": { + "title": "Swim in the Seine — open July & August 2026", + "subtitle": "First time in 102 years", + "image": null, + "actionLabel": null, + "action": { + "type": "continue_conversation", + "context": "Tell me about swimming in the Seine" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "su1" + }, + { + "type": "element", + "typeName": "ListItem", + "props": { + "title": "Open-air cinema at Parc de la Villette", + "subtitle": "Free films under the stars", + "image": null, + "actionLabel": null, + "action": { + "type": "continue_conversation", + "context": "Tell me about the open-air cinema at Parc de la Villette" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "su2" + }, + { + "type": "element", + "typeName": "ListItem", + "props": { + "title": "Bastille Day celebrations on July 14", + "subtitle": "Fireworks at the Eiffel Tower", + "image": null, + "actionLabel": null, + "action": { + "type": "continue_conversation", + "context": "What happens in Paris on Bastille Day?" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "su3" + } + ], + "variant": "number" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "summerList" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabSummer" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "whenTabs" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "secWhen" + } + ], + "isFoldable": false + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "sectionsBlock" + }, + { + "type": "element", + "typeName": "Buttons", + "props": { + "buttons": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Plan a Trip to Paris", + "action": { + "type": "continue_conversation", + "context": "Help me plan a trip to Paris" + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btn1" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Best Hotels in Paris", + "action": { + "type": "continue_conversation", + "context": "Show me the best hotels in Paris" + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btn2" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Build a Paris Itinerary", + "action": { + "type": "continue_conversation", + "context": "Build a 5-day Paris itinerary for me" + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btn3" + } + ], + "direction": "row" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "actionBtns" + } + ], + "sources": [ + { + "title": "Paris Travel Guide 2025", + "sourceName": "Travel and Tour World", + "url": "https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/" + }, + { + "title": "Best Things to Do in Paris 2026", + "sourceName": "Time Out Paris", + "url": "http://www.timeout.fr/paris/en/for-tourists" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 63, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "chat-example-2", + "schema": "chat", + "input": "Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "CardHeader", + "props": { + "title": "Analytics Dashboard", + "subtitle": "April 2026 · Business Performance Overview" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "pageHeader" + }, + { + "type": "element", + "typeName": "SnippetCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "total-revenue", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "circle-dollar-sign", + "category": "finance" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Total Revenue", + "subtitle": "Month to date", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "$284,500", + "subtext": "+12.4%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1" + }, + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "active-users", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "users", + "category": "people" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Active Users", + "subtitle": "Monthly active users", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "47,320", + "subtext": "+6.8%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2" + }, + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "conversion-rate", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "trending-up", + "category": "charts" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Conversion Rate", + "subtitle": "Avg. this month", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "5.7%", + "subtext": "+0.9%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3" + }, + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "churn-rate", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "user-minus", + "category": "people" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi4icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Churn Rate", + "subtitle": "Monthly customer churn", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi4lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "2.1%", + "subtext": "-0.4%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi4rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi4" + } + ], + "layout": "grid", + "responsive": true + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpiBlock" + }, + { + "type": "element", + "typeName": "SectionBlock", + "props": { + "sections": [ + { + "type": "element", + "typeName": "SectionItem", + "props": { + "value": "users", + "trigger": "User Activity", + "content": [ + { + "type": "element", + "typeName": "Tabs", + "props": { + "items": [ + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "growth", + "trigger": "User Growth", + "content": [ + { + "type": "element", + "typeName": "LineChart", + "props": { + "labels": [ + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + "Jan", + "Feb", + "Mar", + "Apr" + ], + "series": [ + { + "type": "element", + "typeName": "Series", + "props": { + "category": "DAU", + "values": [ + 5.1, + 5.4, + 5.8, + 6.2, + 6.7, + 7.1, + 7.6, + 8, + 8.4, + 8.9, + 9.3, + 9.8 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "dauSeries" + }, + { + "type": "element", + "typeName": "Series", + "props": { + "category": "MAU", + "values": [ + 28.4, + 30.1, + 31.8, + 33.5, + 35.2, + 37.1, + 38.8, + 40.4, + 42.1, + 43.9, + 45.6, + 47.3 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "mauSeries" + } + ], + "variant": "natural", + "xLabel": "Month", + "yLabel": "Users (k)" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "growthChart" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabGrowth" + }, + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "retention", + "trigger": "Cohort Retention", + "content": [ + { + "type": "element", + "typeName": "LineChart", + "props": { + "labels": [ + "Month 0", + "Month 1", + "Month 2", + "Month 3", + "Month 4", + "Month 5", + "Month 6" + ], + "series": [ + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Jan Cohort", + "values": [ + 100, + 80, + 70, + 62, + 56, + 51, + 47 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "cohortJan" + }, + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Feb Cohort", + "values": [ + 100, + 83, + 73, + 65, + 59, + 54, + 50 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "cohortFeb" + }, + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Mar Cohort", + "values": [ + 100, + 86, + 76, + 68, + 62, + 0, + 0 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "cohortMar" + } + ], + "variant": "natural", + "xLabel": "Month Since Signup", + "yLabel": "Retention (%)" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "retentionChart" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabRetention" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "userTabs" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "secUsers" + }, + { + "type": "element", + "typeName": "SectionItem", + "props": { + "value": "channels", + "trigger": "Acquisition Channels", + "content": [ + { + "type": "element", + "typeName": "Tabs", + "props": { + "items": [ + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "channel-bar", + "trigger": "Revenue by Channel", + "content": [ + { + "type": "element", + "typeName": "HorizontalBarChart", + "props": { + "labels": [ + "Organic Search", + "Paid Ads", + "Referral Program", + "Partner Network", + "Direct / Brand", + "Email Campaigns" + ], + "series": [ + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Revenue ($k)", + "values": [ + 82.4, + 68.1, + 54.6, + 38.2, + 26.8, + 14.4 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "channelSeries" + } + ], + "variant": "grouped", + "xLabel": "Revenue ($k)", + "yLabel": "Channel" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "channelBarChart" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabChannelBar" + }, + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "channel-table", + "trigger": "Full Breakdown", + "content": [ + { + "type": "element", + "typeName": "Table", + "props": { + "columns": [ + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Channel", + "data": [ + "Organic Search", + "Paid Ads", + "Referral Program", + "Partner Network", + "Direct / Brand", + "Email Campaigns" + ], + "type": "string" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "colChannel" + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Leads", + "data": [ + 4210, + 3180, + 2050, + 1120, + 1290, + 820 + ], + "type": "number" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "colLeads" + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Conv. Rate", + "data": [ + "6.4%", + "5.1%", + "9.4%", + "11.8%", + "5.8%", + "8.1%" + ], + "type": "string" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "colConv" + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "CAC ($)", + "data": [ + 188, + 395, + 132, + 109, + 218, + 154 + ], + "type": "number" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "colCac" + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Revenue ($k)", + "data": [ + 82.4, + 68.1, + 54.6, + 38.2, + 26.8, + 14.4 + ], + "type": "number" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "colRevenue" + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Status", + "data": [ + "Scaling", + "Optimizing", + "Scaling", + "Growing", + "Stable", + "Stable" + ], + "type": "string" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "colStatus" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "channelTable" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabChannelTable" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "channelTabs" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "secChannels" + } + ], + "isFoldable": false + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "sections" + }, + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "Support Health & Marketing ROI", + "description": "Click a card to explore deeper insights" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "deepDiveHeader" + }, + { + "type": "element", + "typeName": "CompositeCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "CompositeCardItem", + "props": { + "id": "support-health", + "header": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "headphones", + "category": "communication" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "supportIcon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Support Health", + "subtitle": "Ticket volume & resolution trends", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "supportHeader" + }, + "body": [ + { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "94.2% CSAT", + "subtext": "Customer Satisfaction Score", + "trend": { + "direction": "up", + "value": 2.1 + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "supportMetric" + }, + { + "type": "element", + "typeName": "BarChart", + "props": { + "labels": [ + "Jan", + "Feb", + "Mar", + "Apr" + ], + "series": [ + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Opened", + "values": [ + 341, + 327, + 308, + 289 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "openSeries" + }, + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Resolved", + "values": [ + 319, + 318, + 301, + 283 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "resolvedSeries" + } + ], + "variant": "grouped", + "xLabel": "Month", + "yLabel": "Tickets" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "supportChart" + }, + { + "type": "element", + "typeName": "EntityList", + "props": { + "rows": [ + { + "left": "Avg. Resolution Time", + "right": "4h 12m", + "rightVariant": "text" + }, + { + "left": "First Contact Resolution", + "right": "78.4%", + "rightVariant": "number" + }, + { + "left": "Escalation Rate", + "right": "6.2%", + "rightVariant": "number" + } + ], + "size": "small" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "supportList" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "cardSupport" + }, + { + "type": "element", + "typeName": "CompositeCardItem", + "props": { + "id": "marketing-roi", + "header": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "megaphone", + "category": "communication" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "marketingIcon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Marketing ROI", + "subtitle": "Spend vs. pipeline generated", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "marketingHeader" + }, + "body": [ + { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "3.8x Blended ROI", + "subtext": "Return on Ad Spend", + "trend": { + "direction": "up", + "value": 0.4 + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "marketingMetric" + }, + { + "type": "element", + "typeName": "AreaChart", + "props": { + "labels": [ + "Jan", + "Feb", + "Mar", + "Apr" + ], + "series": [ + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Ad Spend", + "values": [ + 44, + 46.8, + 49.2, + 51.6 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "spendSeries" + }, + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Pipeline Generated", + "values": [ + 158.2, + 171.5, + 184.9, + 196.1 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "pipelineSeries" + } + ], + "variant": "natural", + "xLabel": "Month", + "yLabel": "Value ($k)" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "marketingChart" + }, + { + "type": "element", + "typeName": "EntityList", + "props": { + "rows": [ + { + "left": "Total Ad Spend (Apr)", + "right": "$51,600", + "rightVariant": "number" + }, + { + "left": "Cost per Lead", + "right": "$48.20", + "rightVariant": "number" + }, + { + "left": "Top Channel", + "right": "Organic Search", + "rightVariant": "text" + } + ], + "size": "small" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "marketingList" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "cardMarketing" + } + ], + "layout": "grid", + "responsive": true, + "action": { + "type": "continue_conversation", + "context": "Explore this deep-dive area in more detail" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "compositeCards" + }, + { + "type": "element", + "typeName": "Buttons", + "props": { + "buttons": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Break Down by Channel", + "action": { + "type": "continue_conversation", + "context": "Break down this month's revenue by acquisition channel" + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btnChannels" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Forecast Next Quarter", + "action": { + "type": "continue_conversation", + "context": "Forecast revenue and active users for next quarter" + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btnForecast" + } + ], + "direction": "row" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "actionButtons" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 74, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "chat-example-3", + "schema": "chat", + "input": "Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "CardHeader", + "props": { + "title": "Plan Your Trip", + "subtitle": "A few ideas to spark inspiration — then tell me your preferences" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "header" + }, + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Tap a style to jump straight in, or fill the quick form below for a tailored plan." + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "intro" + }, + { + "type": "element", + "typeName": "VisualCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Tropical Beach Escape", + "subtext": "Overwater villas & snorkeling", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp1body" + }, + "id": "inspo-beach", + "bgImageSrc": "https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "Relaxation", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "umbrella", + "category": "travel" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp1icon" + }, + "size": "sm", + "variant": "info" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp1tag" + }, + "bgImageAlt": "Maldives overwater villas" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp1" + }, + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Mountain Adventure", + "subtext": "Trekking & epic views", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp2body" + }, + "id": "inspo-mountain", + "bgImageSrc": "https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "Active", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "mountain", + "category": "nature" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp2icon" + }, + "size": "sm", + "variant": "warning" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp2tag" + }, + "bgImageAlt": "Trekking in the Peruvian Andes" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp2" + } + ], + "layout": "grid", + "responsive": true, + "action": { + "type": "continue_conversation", + "context": "Plan me a trip in this style with destinations, itinerary, and costs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "inspoCards" + }, + { + "type": "element", + "typeName": "Form", + "props": { + "name": "trip-planner", + "buttons": { + "type": "element", + "typeName": "Buttons", + "props": { + "buttons": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Plan My Trip", + "action": { + "type": "continue_conversation", + "context": "Help me plan a trip based on my form submission" + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btnSubmit" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Just Surprise Me", + "action": { + "type": "continue_conversation", + "context": "Skip the form and surprise me with a destination and itinerary" + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btnSkip" + } + ], + "direction": "row" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "formButtons" + }, + "fields": [ + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Destination", + "input": { + "type": "element", + "typeName": "Input", + "props": { + "name": "destination", + "placeholder": "e.g. Tokyo, Japan — or leave blank", + "type": "text" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "destinationInput" + }, + "hint": "Leave blank if you'd like suggestions" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcDestination" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Travel Dates", + "input": { + "type": "element", + "typeName": "DatePicker", + "props": { + "name": "travel-dates", + "mode": "range", + "rules": { + "required": true + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "datesPicker" + }, + "hint": "Select your start and end dates" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcDates" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Number of Travellers", + "input": { + "type": "element", + "typeName": "Select", + "props": { + "name": "num-travellers", + "items": [ + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "1", + "label": "1 — Solo" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tr1" + }, + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "2", + "label": "2 — Couple" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tr2" + }, + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "3-4", + "label": "3–4 People" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tr3" + }, + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "5+", + "label": "5+ People" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tr4" + } + ], + "placeholder": "Select number of travellers", + "rules": { + "required": true + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "travellersSelect" + }, + "hint": "How many people are travelling?" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcTravellers" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Trip Type", + "input": { + "type": "element", + "typeName": "OptionCards", + "props": { + "name": "trip-type", + "type": "single", + "items": [ + { + "type": "element", + "typeName": "OptionCard", + "props": { + "value": "adventure", + "title": "Adventure", + "subtitle": "Hiking, trekking & outdoor activities", + "topContent": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "mountain", + "category": "nature" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc1icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc1" + }, + { + "type": "element", + "typeName": "OptionCard", + "props": { + "value": "beach", + "title": "Beach & Relaxation", + "subtitle": "Sun, sand & leisure", + "topContent": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "waves", + "category": "nature" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc2icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc2" + }, + { + "type": "element", + "typeName": "OptionCard", + "props": { + "value": "cultural", + "title": "Cultural & Historical", + "subtitle": "Museums, heritage & local experiences", + "topContent": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "landmark", + "category": "buildings" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc3icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc3" + }, + { + "type": "element", + "typeName": "OptionCard", + "props": { + "value": "city", + "title": "City Break", + "subtitle": "Urban exploration & nightlife", + "topContent": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "building-2", + "category": "buildings" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc4icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc4" + } + ], + "rules": { + "required": true + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tripTypeCards" + }, + "hint": "What kind of trip are you planning?" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcTripType" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Estimated Budget (per person)", + "input": { + "type": "element", + "typeName": "Slider", + "props": { + "name": "budget", + "variant": "discrete", + "min": 500, + "max": 10000, + "step": 500, + "defaultValue": [ + 2500 + ], + "label": "Budget (USD)" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "budgetSlider" + }, + "hint": "Drag to set your per-person budget in USD" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcBudget" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Accommodation Preference", + "input": { + "type": "element", + "typeName": "Chips", + "props": { + "name": "accommodation", + "type": "multiple", + "items": [ + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "hotel", + "label": "Hotel", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "building", + "category": "buildings" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch1icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch1" + }, + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "resort", + "label": "Resort", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "umbrella", + "category": "travel" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch2icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch2" + }, + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "airbnb", + "label": "Vacation Rental", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "home", + "category": "home" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch3icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch3" + }, + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "camping", + "label": "Camping / Glamping", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "tent", + "category": "nature" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch4icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch4" + } + ], + "rules": {}, + "defaultValue": [ + "hotel" + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "stayChips" + }, + "hint": "Select all that apply" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcStay" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Special Requests or Notes", + "input": { + "type": "element", + "typeName": "TextArea", + "props": { + "name": "special-requests", + "placeholder": "e.g. vegetarian meals, wheelchair access, honeymoon surprise...", + "rows": 4 + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "notesArea" + }, + "hint": "Any dietary needs, accessibility requirements, or specific interests?" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcNotes" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "form" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 50, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "chat-example-4", + "schema": "chat", + "input": "Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "CardHeader", + "props": { + "title": "Retro-Energetic Indian Tracks", + "subtitle": "New Hindi releases with 80s/90s dance DNA" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "header" + }, + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video." + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "intro" + }, + { + "type": "element", + "typeName": "VisualCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Tamma Tamma", + "subtext": "Dhurandhar · Ranveer Singh", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v1body" + }, + "id": "tamma", + "bgImageSrc": "https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "80s Electro-Disco", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "disc-3", + "category": "multimedia" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v1icon" + }, + "size": "sm", + "variant": "success" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v1tag" + }, + "bgImageAlt": "Tamma Tamma video poster" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v1" + }, + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Sajan Re", + "subtext": "Nora Fatehi · Badshah", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v2body" + }, + "id": "sajan", + "bgImageSrc": "https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "Synthwave Electro", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "music", + "category": "multimedia" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v2icon" + }, + "size": "sm", + "variant": "info" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v2tag" + }, + "bgImageAlt": "Sajan Re video poster" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v2" + } + ], + "layout": "grid", + "responsive": true, + "action": { + "type": "continue_conversation", + "context": "Tell me more about this track and its retro influences" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "posters" + }, + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "Watch the Exact Videos", + "description": "Each button opens that track's official video" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "linksHeader" + }, + { + "type": "element", + "typeName": "CompositeCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "CompositeCardItem", + "props": { + "id": "t-tamma", + "header": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "disc-3", + "category": "multimedia" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Tamma Tamma", + "subtitle": "Bappi Lahiri classic, electro-funk rework", + "bold": true, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1h" + }, + "body": [ + { + "type": "element", + "typeName": "Text", + "props": { + "variant": "text", + "value": "Heavy analog synths and brass over a fast disco groove.", + "subtext": "Retro Electro-Disco", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1body" + }, + { + "type": "element", + "typeName": "TagBlock", + "props": { + "tags": [ + "2026 Film Hit", + "Peak Party" + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1tags" + } + ], + "footer": { + "button": { + "type": "element", + "typeName": "Button", + "props": { + "label": "Watch on YouTube", + "action": { + "type": "open_url", + "url": "https://www.youtube.com/watch?v=PQHeOb0Q9oo" + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1btn" + } + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1" + }, + { + "type": "element", + "typeName": "CompositeCardItem", + "props": { + "id": "t-sajan", + "header": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "music", + "category": "multimedia" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t2icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Sajan Re", + "subtitle": "Nora Fatehi · Badshah · Sanjoy", + "bold": true, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t2h" + }, + "body": [ + { + "type": "element", + "typeName": "Text", + "props": { + "variant": "text", + "value": "Synthwave melody hooks over a modern club beat.", + "subtext": "Retro-Fusion Electro", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t2body" + }, + { + "type": "element", + "typeName": "TagBlock", + "props": { + "tags": [ + "Club Anthem", + "Nora x Badshah" + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t2tags" + } + ], + "footer": { + "button": { + "type": "element", + "typeName": "Button", + "props": { + "label": "Watch on YouTube", + "action": { + "type": "open_url", + "url": "https://www.youtube.com/watch?v=COUSCnFazzc" + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t2btn" + } + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t2" + } + ], + "layout": "grid", + "responsive": true + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "trackCards" + } + ], + "sources": [ + { + "title": "Tamma Tamma (Full Video) - Dhurandhar", + "sourceName": "YouTube (T-Series)", + "url": "https://www.youtube.com/watch?v=PQHeOb0Q9oo" + }, + { + "title": "Sajan Re (Official Music Video)", + "sourceName": "YouTube (T-Series)", + "url": "https://www.youtube.com/watch?v=COUSCnFazzc" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 28, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "chat-example-5", + "schema": "chat", + "input": "Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Top Languages", + "size": "large-heavy" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "title" + }, + { + "type": "element", + "typeName": "Table", + "props": { + "columns": [ + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Language", + "data": [ + "Python", + "JavaScript", + "Java" + ] + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Users (M)", + "data": [ + 15.7, + 14.2, + 12.1 + ] + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Year", + "data": [ + 1991, + 1995, + 1995 + ] + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tbl" + }, + { + "type": "element", + "typeName": "FollowUpBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "FollowUpItem", + "props": { + "text": "Tell me more about Python" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fu1" + }, + { + "type": "element", + "typeName": "FollowUpItem", + "props": { + "text": "Show me a JavaScript comparison" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fu2" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "followUps" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 9, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "basic", + "schema": "test", + "input": "root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "Hi" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Go" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "b1" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 3, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "missing-required", + "schema": "test", + "input": "root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Go" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "b1" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 3, + "errors": [ + { + "code": "missing-required", + "component": "Text", + "path": "/text", + "message": "missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")", + "statementId": "t1" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "null-required-with-default", + "schema": "test", + "input": "root = Card([t1])\nt1 = Text(null)", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [ + { + "code": "null-required", + "component": "Text", + "path": "/text", + "message": "required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")", + "statementId": "t1" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "required-default-fills", + "schema": "test", + "input": "root = Card([x])\nx = Tagged(1, true, \"x\", null)", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Tagged", + "props": { + "count": 1, + "flag": true, + "kind": "x", + "tone": "neutral" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "x" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "unknown-component", + "schema": "test", + "input": "root = Card([Mystery(\"a\"), Text(\"b\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "b" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [ + { + "code": "unknown-component", + "component": "Mystery", + "path": "", + "message": "Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged", + "statementId": "root" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "excess-args", + "schema": "test", + "input": "root = Card([Text(\"a\", \"m\", \"extra\", 4)])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "a", + "size": "m" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [ + { + "code": "excess-args", + "component": "Text", + "path": "", + "message": "Text takes 2 arg(s), got 4 (2 excess dropped)", + "statementId": "root" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "type-mismatch-scalar", + "schema": "test", + "input": "root = Card([Text(42)], 7)", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [ + { + "code": "type-mismatch", + "component": "Text", + "path": "/text", + "message": "field \"/text\" expects string but got number", + "statementId": "root" + }, + { + "code": "type-mismatch", + "component": "Card", + "path": "/title", + "message": "field \"/title\" expects string but got number", + "statementId": "root" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "enum-mismatch", + "schema": "test", + "input": "root = Card([Text(\"a\", \"xl\"), Button(\"b\", null, \"tertiary\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "a", + "size": "m" + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "b", + "action": null + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [ + { + "code": "type-mismatch", + "component": "Text", + "path": "/size", + "message": "field \"/size\" expects one of [\"s\", \"m\", \"l\"] but got \"xl\"", + "statementId": "root" + }, + { + "code": "type-mismatch", + "component": "Button", + "path": "/variant", + "message": "field \"/variant\" expects one of [\"primary\", \"secondary\"] but got \"tertiary\"", + "statementId": "root" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "enum-partial-deferred", + "schema": "test", + "input": "root = Card([Text(\"a\", \"x", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "a", + "size": "x" + }, + "partial": true, + "hasDynamicProps": false + } + ] + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": true, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "integer-boolean-const", + "schema": "test", + "input": "root = Card([x])\nx = Tagged(1.5, \"yes\", \"y\", \"loud\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Tagged", + "props": { + "count": 1.5, + "tone": "loud" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "x" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [ + { + "code": "type-mismatch", + "component": "Tagged", + "path": "/flag", + "message": "field \"/flag\" expects boolean but got string", + "statementId": "x" + }, + { + "code": "type-mismatch", + "component": "Tagged", + "path": "/kind", + "message": "field \"/kind\" expects one of [\"x\"] but got \"y\"", + "statementId": "x" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "nested-object", + "schema": "test", + "input": "root = Card([c1, c2, c3])\nc1 = Chart([\"a\"], [1], {unit: \"kg\"})\nc2 = Chart([\"a\"], [1], {scale: 2})\nc3 = Chart([\"a\"], [1], {unit: 5, scale: \"big\"})", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Chart", + "props": { + "labels": [ + "a" + ], + "values": [ + 1 + ], + "meta": { + "unit": "kg" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "c1" + }, + { + "type": "element", + "typeName": "Chart", + "props": { + "labels": [ + "a" + ], + "values": [ + 1 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "c2" + }, + { + "type": "element", + "typeName": "Chart", + "props": { + "labels": [ + "a" + ], + "values": [ + 1 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "c3" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 4, + "errors": [ + { + "code": "missing-required", + "component": "Chart", + "path": "/meta/unit", + "message": "missing required field \"/meta/unit\"", + "statementId": "c2" + }, + { + "code": "type-mismatch", + "component": "Chart", + "path": "/meta/unit", + "message": "field \"/meta/unit\" expects string but got number", + "statementId": "c3" + }, + { + "code": "type-mismatch", + "component": "Chart", + "path": "/meta/scale", + "message": "field \"/meta/scale\" expects number but got string", + "statementId": "c3" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "array-items-pruned", + "schema": "test", + "input": "root = Card([Chart([\"a\", 2, \"c\"], [1, \"x\", 3])])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Chart", + "props": { + "labels": [ + "a", + "c" + ], + "values": [ + 1, + 3 + ] + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [ + { + "code": "type-mismatch", + "component": "Chart", + "path": "/labels/1", + "message": "field \"/labels/1\" expects string but got number", + "statementId": "root" + }, + { + "code": "type-mismatch", + "component": "Chart", + "path": "/values/1", + "message": "field \"/values/1\" expects number but got string", + "statementId": "root" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "element-in-data-slot", + "schema": "test", + "input": "root = Card([Chart([Text(\"a\")], [1])])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Chart", + "props": { + "labels": [], + "values": [ + 1 + ] + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [ + { + "code": "type-mismatch", + "component": "Chart", + "path": "/labels/0", + "message": "field \"/labels/0\" expects string but got component \"Text\"", + "statementId": "root" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "unresolved-and-orphaned", + "schema": "test", + "input": "root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "x" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "a" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [ + "missing" + ], + "orphaned": [ + "lonely" + ], + "statementCount": 3, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "cycle", + "schema": "test", + "input": "root = Card([a])\na = Card([b])\nb = Card([a])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Card", + "props": { + "children": [] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "b" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "a" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [ + "a" + ], + "orphaned": [], + "statementCount": 3, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "self-reference", + "schema": "test", + "input": "root = Card([root])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Card", + "props": { + "children": [] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [ + "root" + ], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "no-root-first-component", + "schema": "test", + "input": "x = 1\nmain = Card([Text(\"a\")])\nother = Card([])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "a" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "main" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [ + "x", + "other" + ], + "statementCount": 3, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "root-name-statement", + "schema": "test", + "input": "Card = Card([Text(\"named\")])\nother = Card([])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "named" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "Card" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [ + "other" + ], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "duplicate-ids", + "schema": "test", + "input": "root = Card([a])\na = Text(\"first\")\na = Text(\"second\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "second" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "a" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "only-prose", + "schema": "test", + "input": "Here is your UI, it will appear below.", + "expected": { + "root": null, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 0, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "empty", + "schema": "test", + "input": "", + "expected": { + "root": null, + "meta": { + "incomplete": true, + "unresolved": [], + "orphaned": [], + "statementCount": 0, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "whitespace", + "schema": "test", + "input": " \n\t \n", + "expected": { + "root": null, + "meta": { + "incomplete": true, + "unresolved": [], + "orphaned": [], + "statementCount": 0, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "fences-and-prose", + "schema": "test", + "input": "Sure! Here it is:\n```openui\nroot = Card([a])\na = Text(\"fenced\")\n```\nAnything else?", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "fenced" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "a" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "multiple-fences", + "schema": "test", + "input": "```\nroot = Card([a])\n```\nand\n```\na = Text(\"second block\")\n```", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "second block" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "a" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "unclosed-fence", + "schema": "test", + "input": "```openui\nroot = Card([a])\na = Text(\"str", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "str" + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "a" + } + ] + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": true, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "fence-in-string", + "schema": "test", + "input": "root = Card([a])\na = Text(\"use ``` to fence\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "use ``` to fence" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "a" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "comments", + "schema": "test", + "input": "root = Card([a]) // trailing\n# full line\na = Text(\"not // a comment # here\")\n// done", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "not // a comment # here" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "a" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "crlf", + "schema": "test", + "input": "root = Card([a])\r\na = Text(\"windows\")\r\n", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "windows" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "a" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "string-escapes", + "schema": "test", + "input": "root = Card([a, b, c, d])\na = Text(\"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83d\\ude00\")\nb = Text('single \\' quote \\n esc \\q')\nc = Text(\"bad \\x escape\")\nd = Text(\"emoji 😀 and é and 漢字\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "tab\tnew\nquote\" back\\ unié pair😀" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "a" + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": "single ' quote \n esc q" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "b" + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": "bad \\x escape" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "c" + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": "emoji 😀 and é and 漢字" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "d" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 5, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "emoji-outside-strings", + "schema": "test", + "input": "root = Card([a]) 😀\na = Text(\"ok\") ✅", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "ok" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "a" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "unterminated-string", + "schema": "test", + "input": "root = Card([a])\na = Text(\"streaming tex", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "streaming tex" + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "a" + } + ] + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": true, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "unterminated-escape", + "schema": "test", + "input": "root = Card([a])\na = Text(\"ends with \\", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "ends with \\" + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "a" + } + ] + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": true, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "numbers", + "schema": "test", + "input": "root = Card([Chart([\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"], [-3, 1.5, 1e3, 007, -0, 2.5e-3])])\n$x = 1e\n$y = 1E+2\n$z = 3.", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Chart", + "props": { + "labels": [ + "a", + "b", + "c", + "d", + "e", + "f" + ], + "values": [ + -3, + 1.5, + 1000, + 7, + 0, + 0.0025 + ] + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 4, + "errors": [] + }, + "stateDeclarations": { + "$x": null, + "$y": 100, + "$z": { + "k": "Member", + "obj": { + "k": "Num", + "v": 3 + }, + "field": "?" + } + }, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "operators", + "schema": "test", + "input": "$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": { + "k": "Ternary", + "cond": { + "k": "BinOp", + "op": "||", + "left": { + "k": "BinOp", + "op": "&&", + "left": { + "k": "BinOp", + "op": ">", + "left": { + "k": "BinOp", + "op": "-", + "left": { + "k": "BinOp", + "op": "+", + "left": { + "k": "StateRef", + "n": "$a" + }, + "right": { + "k": "BinOp", + "op": "*", + "left": { + "k": "StateRef", + "n": "$b" + }, + "right": { + "k": "Num", + "v": 2 + } + } + }, + "right": { + "k": "Num", + "v": -1 + } + }, + "right": { + "k": "Num", + "v": 3 + } + }, + "right": { + "k": "UnaryOp", + "op": "!", + "operand": { + "k": "StateRef", + "n": "$c" + } + } + }, + "right": { + "k": "BinOp", + "op": "==", + "left": { + "k": "StateRef", + "n": "$a" + }, + "right": { + "k": "Str", + "v": "1" + } + } + }, + "then": { + "k": "Str", + "v": "yes" + }, + "else": { + "k": "Str", + "v": "no" + } + } + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 3, + "errors": [] + }, + "stateDeclarations": { + "$a": 1, + "$b": "2", + "$c": null + }, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "multiline-ternary", + "schema": "test", + "input": "$on = true\nroot = Card([t])\nt = Text($on\n ? \"enabled\"\n : \"disabled\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": { + "k": "Ternary", + "cond": { + "k": "StateRef", + "n": "$on" + }, + "then": { + "k": "Str", + "v": "enabled" + }, + "else": { + "k": "Str", + "v": "disabled" + } + } + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "t" + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 3, + "errors": [] + }, + "stateDeclarations": { + "$on": true + }, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "member-index", + "schema": "test", + "input": "$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": { + "k": "Member", + "obj": { + "k": "Index", + "obj": { + "k": "Member", + "obj": { + "k": "StateRef", + "n": "$data" + }, + "field": "rows" + }, + "index": { + "k": "Num", + "v": 1 + } + }, + "field": "name" + } + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": { + "k": "Member", + "obj": { + "k": "Member", + "obj": { + "k": "StateRef", + "n": "$data" + }, + "field": "rows" + }, + "field": "name" + } + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": { + "k": "Index", + "obj": { + "k": "StateRef", + "n": "$data" + }, + "index": { + "k": "Str", + "v": "key x" + } + } + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": { + "$data": { + "rows": [ + { + "name": "a" + }, + { + "name": "b" + } + ], + "key x": 1 + } + }, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "builtins", + "schema": "test", + "input": "$items = [3, 1, 2]\nroot = Card([Text(\"\" + @Count($items)), Text(\"\" + @Sum($items)), Text(@Round(2.555, 2) + \"\")])\nbare = Count($items)", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": { + "k": "BinOp", + "op": "+", + "left": { + "k": "Str", + "v": "" + }, + "right": { + "k": "Comp", + "name": "Count", + "args": [ + { + "k": "StateRef", + "n": "$items" + } + ] + } + } + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": { + "k": "BinOp", + "op": "+", + "left": { + "k": "Str", + "v": "" + }, + "right": { + "k": "Comp", + "name": "Sum", + "args": [ + { + "k": "StateRef", + "n": "$items" + } + ] + } + } + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": { + "k": "BinOp", + "op": "+", + "left": { + "k": "Comp", + "name": "Round", + "args": [ + { + "k": "Num", + "v": 2.555 + }, + { + "k": "Num", + "v": 2 + } + ] + }, + "right": { + "k": "Str", + "v": "" + } + } + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [ + "bare" + ], + "statementCount": 3, + "errors": [] + }, + "stateDeclarations": { + "$items": [ + 3, + 1, + 2 + ] + }, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "actions", + "schema": "test", + "input": "$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Inc", + "action": { + "k": "Comp", + "name": "Action", + "args": [ + { + "k": "Arr", + "els": [ + { + "k": "Comp", + "name": "Set", + "args": [ + { + "k": "StateRef", + "n": "$n" + }, + { + "k": "BinOp", + "op": "+", + "left": { + "k": "StateRef", + "n": "$n" + }, + "right": { + "k": "Num", + "v": 1 + } + } + ] + }, + { + "k": "Comp", + "name": "ToAssistant", + "args": [ + { + "k": "Str", + "v": "Bumped" + }, + { + "k": "Str", + "v": "ctx" + } + ] + } + ] + } + ] + } + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "b1" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Reset", + "action": { + "k": "Comp", + "name": "Action", + "args": [ + { + "k": "Arr", + "els": [ + { + "k": "Comp", + "name": "Reset", + "args": [ + { + "k": "StateRef", + "n": "$n" + } + ] + } + ] + } + ] + } + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "b2" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Docs", + "action": { + "k": "Comp", + "name": "Action", + "args": [ + { + "k": "Arr", + "els": [ + { + "k": "Comp", + "name": "OpenUrl", + "args": [ + { + "k": "Str", + "v": "https://openui.com" + } + ] + } + ] + } + ] + } + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "b3" + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 5, + "errors": [] + }, + "stateDeclarations": { + "$n": 0 + }, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "each", + "schema": "test", + "input": "$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": { + "k": "Comp", + "name": "Each", + "args": [ + { + "k": "StateRef", + "n": "$todos" + }, + { + "k": "Ref", + "n": "todo" + }, + { + "k": "Comp", + "name": "Text", + "args": [ + { + "k": "Member", + "obj": { + "k": "Ref", + "n": "todo" + }, + "field": "title" + } + ], + "mappedProps": { + "text": { + "k": "Member", + "obj": { + "k": "Ref", + "n": "todo" + }, + "field": "title" + } + } + } + ] + } + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": { + "$todos": [ + { + "title": "a", + "done": false + }, + { + "title": "b", + "done": true + } + ] + }, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "query-mutation", + "schema": "test", + "input": "$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": { + "k": "BinOp", + "op": "+", + "left": { + "k": "Member", + "obj": { + "k": "Member", + "obj": { + "k": "RuntimeRef", + "n": "users", + "refType": "query" + }, + "field": "rows" + }, + "field": "length" + }, + "right": { + "k": "Str", + "v": " users" + } + } + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Save", + "action": { + "k": "Comp", + "name": "Action", + "args": [ + { + "k": "Arr", + "els": [ + { + "k": "Comp", + "name": "Run", + "args": [ + { + "k": "RuntimeRef", + "n": "save", + "refType": "mutation" + } + ] + }, + { + "k": "Comp", + "name": "Run", + "args": [ + { + "k": "RuntimeRef", + "n": "users", + "refType": "query" + } + ] + } + ] + } + ] + } + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 4, + "errors": [] + }, + "stateDeclarations": { + "$q": "x", + "$page": null + }, + "queryStatements": [ + { + "statementId": "users", + "toolAST": { + "k": "Str", + "v": "list_users" + }, + "argsAST": { + "k": "Obj", + "entries": [ + [ + "search", + { + "k": "StateRef", + "n": "$q" + } + ], + [ + "page", + { + "k": "StateRef", + "n": "$page" + } + ] + ] + }, + "defaultsAST": { + "k": "Obj", + "entries": [ + [ + "rows", + { + "k": "Arr", + "els": [] + } + ] + ] + }, + "refreshAST": { + "k": "Num", + "v": 30 + }, + "deps": [ + "$q", + "$page" + ], + "complete": true + } + ], + "mutationStatements": [ + { + "statementId": "save", + "toolAST": { + "k": "Str", + "v": "save_user" + }, + "argsAST": { + "k": "Obj", + "entries": [ + [ + "name", + { + "k": "StateRef", + "n": "$q" + } + ] + ] + } + } + ] + } + }, + { + "name": "state-query", + "schema": "test", + "input": "$data = Query(\"get\", {})\nroot = Card([Text(\"x\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "x" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [ + { + "statementId": "$data", + "toolAST": { + "k": "Str", + "v": "get" + }, + "argsAST": { + "k": "Obj", + "entries": [] + }, + "defaultsAST": null, + "refreshAST": null, + "complete": true + } + ], + "mutationStatements": [] + } + }, + { + "name": "inline-query", + "schema": "test", + "input": "root = Card([Text(Query(\"get\", {}))])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [ + { + "code": "inline-reserved", + "component": "Query", + "path": "", + "message": "Query() must be declared as a top-level statement, not used inline as a value", + "statementId": "root" + }, + { + "code": "null-required", + "component": "Text", + "path": "/text", + "message": "required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")", + "statementId": "root" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "assignment", + "schema": "test", + "input": "$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Input", + "props": { + "name": "name", + "value": { + "k": "Assign", + "target": "$v", + "value": { + "k": "StateRef", + "n": "$value" + } + } + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": { + "$v": "", + "$value": null + }, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "object-key-order", + "schema": "test", + "input": "$o = {b: 1, 2: \"two\", a: 3, 1: \"one\", \"10\": 10}\nroot = Card([Text(\"x\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "x" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": { + "$o": { + "1": "one", + "2": "two", + "10": 10, + "b": 1, + "a": 3 + } + }, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "missing-commas", + "schema": "test", + "input": "root = Card([Text(\"a\") Text(\"b\"), Text(\"c\"),])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "a" + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": "b" + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": "c" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "lowercase-builtin-name", + "schema": "test", + "input": "root = Card([Text(@first([1]))])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [ + { + "code": "unknown-component", + "component": "first", + "path": "", + "message": "Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged", + "statementId": "root" + }, + { + "code": "null-required", + "component": "Text", + "path": "/text", + "message": "required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")", + "statementId": "root" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "unknown-tokens", + "schema": "test", + "input": "root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "a" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "combining-characters", + "schema": "test", + "input": "root = Card([Text(\"e\\u0301 cafe\\u0301\"), Text(\"한국어\"), Text(\"ok\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "é café" + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": "한국어" + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": "ok" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "truncated-mid-call", + "schema": "test", + "input": "root = Card([a, b])\na = Text(\"one\")\nb = Button(\"tw", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "one" + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "a" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "tw" + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "b" + } + ] + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": true, + "unresolved": [], + "orphaned": [], + "statementCount": 3, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "truncated-mid-object", + "schema": "test", + "input": "root = Card([Chart([\"a\"], [1], {unit: \"k", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Chart", + "props": { + "labels": [ + "a" + ], + "values": [ + 1 + ], + "meta": { + "unit": "k" + } + }, + "partial": true, + "hasDynamicProps": false + } + ] + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": true, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + } +] diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json new file mode 100644 index 0000000000..f6732fec6e --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json @@ -0,0 +1,4363 @@ +{ + "chat": { + "schema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "Card": { + "$ref": "#/$defs/Card" + }, + "CardHeader": { + "$ref": "#/$defs/CardHeader" + }, + "TextContent": { + "$ref": "#/$defs/TextContent" + }, + "MarkDownRenderer": { + "$ref": "#/$defs/MarkDownRenderer" + }, + "Callout": { + "$ref": "#/$defs/Callout" + }, + "TextCallout": { + "$ref": "#/$defs/TextCallout" + }, + "Image": { + "$ref": "#/$defs/Image" + }, + "ImageBlock": { + "$ref": "#/$defs/ImageBlock" + }, + "ImageGallery": { + "$ref": "#/$defs/ImageGallery" + }, + "CodeBlock": { + "$ref": "#/$defs/CodeBlock" + }, + "Separator": { + "$ref": "#/$defs/Separator" + }, + "Table": { + "$ref": "#/$defs/Table" + }, + "Col": { + "$ref": "#/$defs/Col" + }, + "BarChart": { + "$ref": "#/$defs/BarChart" + }, + "LineChart": { + "$ref": "#/$defs/LineChart" + }, + "AreaChart": { + "$ref": "#/$defs/AreaChart" + }, + "RadarChart": { + "$ref": "#/$defs/RadarChart" + }, + "HorizontalBarChart": { + "$ref": "#/$defs/HorizontalBarChart" + }, + "Series": { + "$ref": "#/$defs/Series" + }, + "PieChart": { + "$ref": "#/$defs/PieChart" + }, + "RadialChart": { + "$ref": "#/$defs/RadialChart" + }, + "SingleStackedBarChart": { + "$ref": "#/$defs/SingleStackedBarChart" + }, + "Slice": { + "$ref": "#/$defs/Slice" + }, + "ScatterChart": { + "$ref": "#/$defs/ScatterChart" + }, + "ScatterSeries": { + "$ref": "#/$defs/ScatterSeries" + }, + "Point": { + "$ref": "#/$defs/Point" + }, + "Form": { + "$ref": "#/$defs/Form" + }, + "FormControl": { + "$ref": "#/$defs/FormControl" + }, + "Label": { + "$ref": "#/$defs/Label" + }, + "Input": { + "$ref": "#/$defs/Input" + }, + "TextArea": { + "$ref": "#/$defs/TextArea" + }, + "Select": { + "$ref": "#/$defs/Select" + }, + "SelectItem": { + "$ref": "#/$defs/SelectItem" + }, + "DatePicker": { + "$ref": "#/$defs/DatePicker" + }, + "Slider": { + "$ref": "#/$defs/Slider" + }, + "CheckBoxGroup": { + "$ref": "#/$defs/CheckBoxGroup" + }, + "CheckBoxItem": { + "$ref": "#/$defs/CheckBoxItem" + }, + "RadioGroup": { + "$ref": "#/$defs/RadioGroup" + }, + "RadioItem": { + "$ref": "#/$defs/RadioItem" + }, + "SwitchGroup": { + "$ref": "#/$defs/SwitchGroup" + }, + "SwitchItem": { + "$ref": "#/$defs/SwitchItem" + }, + "Button": { + "$ref": "#/$defs/Button" + }, + "Buttons": { + "$ref": "#/$defs/Buttons" + }, + "ListBlock": { + "$ref": "#/$defs/ListBlock" + }, + "ListItem": { + "$ref": "#/$defs/ListItem" + }, + "FollowUpBlock": { + "$ref": "#/$defs/FollowUpBlock" + }, + "FollowUpItem": { + "$ref": "#/$defs/FollowUpItem" + }, + "SectionBlock": { + "$ref": "#/$defs/SectionBlock" + }, + "SectionItem": { + "$ref": "#/$defs/SectionItem" + }, + "Tabs": { + "$ref": "#/$defs/Tabs" + }, + "TabItem": { + "$ref": "#/$defs/TabItem" + }, + "Accordion": { + "$ref": "#/$defs/Accordion" + }, + "AccordionItem": { + "$ref": "#/$defs/AccordionItem" + }, + "Steps": { + "$ref": "#/$defs/Steps" + }, + "StepsItem": { + "$ref": "#/$defs/StepsItem" + }, + "Carousel": { + "$ref": "#/$defs/Carousel" + }, + "TagBlock": { + "$ref": "#/$defs/TagBlock" + }, + "Tag": { + "$ref": "#/$defs/Tag" + }, + "EntityList": { + "$ref": "#/$defs/EntityList" + }, + "InlineHeader": { + "$ref": "#/$defs/InlineHeader" + }, + "Icon": { + "$ref": "#/$defs/Icon" + }, + "IconButton": { + "$ref": "#/$defs/IconButton" + }, + "EditableTable": { + "$ref": "#/$defs/EditableTable" + }, + "ChipItem": { + "$ref": "#/$defs/ChipItem" + }, + "Chips": { + "$ref": "#/$defs/Chips" + }, + "OptionCard": { + "$ref": "#/$defs/OptionCard" + }, + "OptionCards": { + "$ref": "#/$defs/OptionCards" + }, + "Text": { + "$ref": "#/$defs/Text" + }, + "BoldText": { + "$ref": "#/$defs/BoldText" + }, + "IconText": { + "$ref": "#/$defs/IconText" + }, + "ImageText": { + "$ref": "#/$defs/ImageText" + }, + "ImageTextLarge": { + "$ref": "#/$defs/ImageTextLarge" + }, + "MetricIndicatorInline": { + "$ref": "#/$defs/MetricIndicatorInline" + }, + "MetricIndicatorWithStrikethrough": { + "$ref": "#/$defs/MetricIndicatorWithStrikethrough" + }, + "SnippetCardItem": { + "$ref": "#/$defs/SnippetCardItem" + }, + "SnippetCardBlock": { + "$ref": "#/$defs/SnippetCardBlock" + }, + "OverviewCardItem": { + "$ref": "#/$defs/OverviewCardItem" + }, + "OverviewCardBlock": { + "$ref": "#/$defs/OverviewCardBlock" + }, + "ContextCardItem": { + "$ref": "#/$defs/ContextCardItem" + }, + "ContextCardBlock": { + "$ref": "#/$defs/ContextCardBlock" + }, + "CompositeCardItem": { + "$ref": "#/$defs/CompositeCardItem" + }, + "CompositeCardBlock": { + "$ref": "#/$defs/CompositeCardBlock" + }, + "VisualCardItem": { + "$ref": "#/$defs/VisualCardItem" + }, + "VisualCardBlock": { + "$ref": "#/$defs/VisualCardBlock" + } + }, + "required": [ + "Card", + "CardHeader", + "TextContent", + "MarkDownRenderer", + "Callout", + "TextCallout", + "Image", + "ImageBlock", + "ImageGallery", + "CodeBlock", + "Separator", + "Table", + "Col", + "BarChart", + "LineChart", + "AreaChart", + "RadarChart", + "HorizontalBarChart", + "Series", + "PieChart", + "RadialChart", + "SingleStackedBarChart", + "Slice", + "ScatterChart", + "ScatterSeries", + "Point", + "Form", + "FormControl", + "Label", + "Input", + "TextArea", + "Select", + "SelectItem", + "DatePicker", + "Slider", + "CheckBoxGroup", + "CheckBoxItem", + "RadioGroup", + "RadioItem", + "SwitchGroup", + "SwitchItem", + "Button", + "Buttons", + "ListBlock", + "ListItem", + "FollowUpBlock", + "FollowUpItem", + "SectionBlock", + "SectionItem", + "Tabs", + "TabItem", + "Accordion", + "AccordionItem", + "Steps", + "StepsItem", + "Carousel", + "TagBlock", + "Tag", + "EntityList", + "InlineHeader", + "Icon", + "IconButton", + "EditableTable", + "ChipItem", + "Chips", + "OptionCard", + "OptionCards", + "Text", + "BoldText", + "IconText", + "ImageText", + "ImageTextLarge", + "MetricIndicatorInline", + "MetricIndicatorWithStrikethrough", + "SnippetCardItem", + "SnippetCardBlock", + "OverviewCardItem", + "OverviewCardBlock", + "ContextCardItem", + "ContextCardBlock", + "CompositeCardItem", + "CompositeCardBlock", + "VisualCardItem", + "VisualCardBlock" + ], + "additionalProperties": false, + "$defs": { + "Card": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + }, + { + "$ref": "#/$defs/ListBlock" + }, + { + "$ref": "#/$defs/FollowUpBlock" + }, + { + "$ref": "#/$defs/SectionBlock" + }, + { + "$ref": "#/$defs/Tabs" + }, + { + "$ref": "#/$defs/Carousel" + } + ] + } + }, + "sources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "title": { + "type": "string" + }, + "sourceName": { + "type": "string" + } + }, + "required": [ + "title", + "sourceName" + ], + "additionalProperties": false + } + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." + }, + "TextContent": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "size": { + "type": "string", + "enum": [ + "small", + "default", + "large", + "small-heavy", + "large-heavy" + ] + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "MarkDownRenderer": { + "type": "object", + "properties": { + "textMarkdown": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": [ + "clear", + "card", + "sunk" + ] + } + }, + "required": [ + "textMarkdown" + ], + "additionalProperties": false, + "description": "Renders markdown text with optional container variant" + }, + "CardHeader": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + } + }, + "additionalProperties": false, + "description": "Header with optional title and subtitle" + }, + "Callout": { + "type": "object", + "properties": { + "variant": { + "type": "string", + "enum": [ + "info", + "warning", + "error", + "success", + "neutral" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "visible": { + "type": "boolean" + } + }, + "required": [ + "variant", + "title", + "description" + ], + "additionalProperties": false, + "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." + }, + "TextCallout": { + "type": "object", + "properties": { + "variant": { + "type": "string", + "enum": [ + "neutral", + "info", + "warning", + "success", + "danger" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false, + "description": "Text callout with variant, title, and description" + }, + "CodeBlock": { + "type": "object", + "properties": { + "language": { + "type": "string" + }, + "codeString": { + "type": "string" + } + }, + "required": [ + "language", + "codeString" + ], + "additionalProperties": false, + "description": "Syntax-highlighted code block" + }, + "Image": { + "type": "object", + "properties": { + "alt": { + "type": "string" + }, + "src": { + "type": "string" + } + }, + "required": [ + "alt" + ], + "additionalProperties": false, + "description": "Image with alt text and optional URL" + }, + "ImageBlock": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + } + }, + "required": [ + "src" + ], + "additionalProperties": false, + "description": "Image block with loading state" + }, + "ImageGallery": { + "type": "object", + "properties": { + "images": { + "type": "array", + "items": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "details": { + "type": "string" + } + }, + "required": [ + "src" + ], + "additionalProperties": false + } + } + }, + "required": [ + "images" + ], + "additionalProperties": false, + "description": "Gallery grid of images with modal preview" + }, + "Separator": { + "type": "object", + "properties": { + "orientation": { + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + }, + "decorative": { + "type": "boolean" + } + }, + "additionalProperties": false, + "description": "Visual divider between content sections" + }, + "HorizontalBarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "grouped", + "stacked" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Horizontal bars; prefer when category labels are long or for ranked lists" + }, + "Series": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "category", + "values" + ], + "additionalProperties": false, + "description": "One data series" + }, + "RadarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Spider/web chart; use for comparing multiple variables across one or more entities" + }, + "PieChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + }, + "variant": { + "type": "string", + "enum": [ + "pie", + "donut" + ] + }, + "appearance": { + "type": "string", + "enum": [ + "circular", + "semiCircular" + ] + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" + }, + "RadialChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" + }, + "SingleStackedBarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" + }, + "ScatterChart": { + "type": "object", + "properties": { + "datasets": { + "type": "array", + "items": { + "$ref": "#/$defs/ScatterSeries" + } + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + } + }, + "required": [ + "datasets" + ], + "additionalProperties": false, + "description": "X/Y scatter plot; use for correlations, distributions, and clustering" + }, + "ScatterSeries": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "points": { + "type": "array", + "items": { + "$ref": "#/$defs/Point" + } + } + }, + "required": [ + "name", + "points" + ], + "additionalProperties": false, + "description": "Named dataset" + }, + "Point": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "z": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ], + "additionalProperties": false, + "description": "Data point with numeric coordinates" + }, + "AreaChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "linear", + "natural", + "step" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Filled area under lines; use for cumulative totals or volume trends over time" + }, + "BarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "grouped", + "stacked" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Vertical bars; use for comparing values across categories with one or more series" + }, + "LineChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "linear", + "natural", + "step" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Lines over categories; use for trends and continuous data over time" + }, + "Table": { + "type": "object", + "properties": { + "columns": { + "type": "array", + "items": { + "$ref": "#/$defs/Col" + } + } + }, + "required": [ + "columns" + ], + "additionalProperties": false, + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "data": {}, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "action" + ] + } + }, + "required": [ + "label", + "data" + ], + "additionalProperties": false, + "description": "Column definition — holds label + data array" + }, + "TagBlock": { + "type": "object", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "tags" + ], + "additionalProperties": false, + "description": "tags is an array of strings; optional size sm | md | lg" + }, + "Form": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "buttons": { + "$ref": "#/$defs/Buttons" + }, + "fields": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/FormControl" + } + } + }, + "required": [ + "name", + "buttons", + "fields" + ], + "additionalProperties": false, + "description": "Form container with fields and explicit action buttons" + }, + "Buttons": { + "type": "object", + "properties": { + "buttons": { + "type": "array", + "items": { + "$ref": "#/$defs/Button" + } + }, + "direction": { + "type": "string", + "enum": [ + "row", + "column" + ] + } + }, + "required": [ + "buttons" + ], + "additionalProperties": false, + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "Button": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "variant": { + "type": "string", + "enum": [ + "primary", + "secondary", + "tertiary" + ] + }, + "type": { + "type": "string", + "enum": [ + "normal", + "destructive" + ] + }, + "size": { + "type": "string", + "enum": [ + "extra-small", + "small", + "medium", + "large" + ] + } + }, + "required": [ + "label" + ], + "additionalProperties": false, + "description": "Clickable button" + }, + "FormControl": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "input": { + "anyOf": [ + { + "$ref": "#/$defs/Input" + }, + { + "$ref": "#/$defs/TextArea" + }, + { + "$ref": "#/$defs/Select" + }, + { + "$ref": "#/$defs/DatePicker" + }, + { + "$ref": "#/$defs/Slider" + }, + { + "$ref": "#/$defs/CheckBoxGroup" + }, + { + "$ref": "#/$defs/RadioGroup" + }, + { + "$ref": "#/$defs/Chips" + }, + { + "$ref": "#/$defs/OptionCards" + } + ] + }, + "hint": { + "type": "string" + } + }, + "required": [ + "label", + "input" + ], + "additionalProperties": false, + "description": "Field with label, input component, and optional hint text" + }, + "Input": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "placeholder": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "text", + "email", + "password", + "number", + "url" + ] + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "TextArea": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "placeholder": { + "type": "string" + }, + "rows": { + "type": "number" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "Select": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/SelectItem" + } + }, + "placeholder": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + }, + "size": { + "type": "string", + "enum": [ + "small", + "medium", + "large" + ] + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "SelectItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false, + "description": "Option for Select" + }, + "DatePicker": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "mode": { + "type": "string", + "enum": [ + "single", + "range" + ] + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": {} + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "Slider": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": [ + "continuous", + "discrete" + ] + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "step": { + "type": "number" + }, + "defaultValue": { + "type": "array", + "items": { + "type": "number" + } + }, + "label": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "name", + "variant", + "min", + "max" + ], + "additionalProperties": false, + "description": "Numeric slider input; supports continuous and discrete (stepped) variants" + }, + "CheckBoxGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/CheckBoxItem" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "CheckBoxItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "defaultChecked": { + "type": "boolean" + } + }, + "required": [ + "label", + "description", + "name" + ], + "additionalProperties": false + }, + "RadioGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/RadioItem" + } + }, + "defaultValue": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "RadioItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "description", + "value" + ], + "additionalProperties": false + }, + "Chips": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "default": "multiple", + "type": "string", + "enum": [ + "single", + "multiple" + ] + }, + "items": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/ChipItem" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "defaultValue": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "name", + "type", + "items" + ], + "additionalProperties": false, + "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." + }, + "ChipItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "disabled": { + "type": "boolean" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false, + "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." + }, + "Icon": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "category": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false, + "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." + }, + "OptionCards": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "default": "single", + "type": "string", + "enum": [ + "single", + "multiple" + ] + }, + "items": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/OptionCard" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "defaultValue": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "name", + "type", + "items" + ], + "additionalProperties": false, + "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." + }, + "OptionCard": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "topContent": { + "anyOf": [ + { + "$ref": "#/$defs/Icon" + }, + { + "$ref": "#/$defs/Image" + } + ] + }, + "disabled": { + "type": "boolean" + } + }, + "required": [ + "value", + "title" + ], + "additionalProperties": false, + "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." + }, + "IconButton": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "variant": { + "type": "string", + "enum": [ + "primary", + "secondary", + "tertiary" + ] + }, + "size": { + "type": "string", + "enum": [ + "extra-small", + "small", + "medium", + "large" + ] + }, + "shape": { + "type": "string", + "enum": [ + "square", + "circle" + ] + } + }, + "required": [ + "name", + "icon" + ], + "additionalProperties": false, + "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." + }, + "Steps": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/StepsItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Step-by-step guide" + }, + "StepsItem": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "details": { + "type": "string" + } + }, + "required": [ + "title", + "details" + ], + "additionalProperties": false, + "description": "title and details text for one step" + }, + "InlineHeader": { + "type": "object", + "properties": { + "heading": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "heading" + ], + "additionalProperties": false, + "description": "Compact section heading with an optional one-line description, for use inside cards." + }, + "EntityList": { + "type": "object", + "properties": { + "rows": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + } + }, + "size": { + "default": "default", + "type": "string", + "enum": [ + "small", + "default" + ] + }, + "header": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + }, + "footer": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + } + }, + "required": [ + "rows", + "size" + ], + "additionalProperties": false, + "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." + }, + "EditableTable": { + "type": "object", + "properties": { + "name": { + "default": "", + "type": "string" + }, + "columns": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "text", + "number", + "date-single", + "select", + "url" + ] + }, + "key": { + "default": "default", + "type": "string" + }, + "header": { + "default": "", + "type": "string" + }, + "width": { + "type": "number" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false + } + } + }, + "required": [ + "type", + "key", + "header" + ], + "additionalProperties": false + } + }, + "data": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + } + }, + "required": [ + "id", + "values" + ], + "additionalProperties": false + } + } + }, + "required": [ + "name", + "columns", + "data" + ], + "additionalProperties": false, + "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" + }, + "SnippetCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/SnippetCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." + }, + "SnippetCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "lhs": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + } + ] + }, + "rhs": { + "anyOf": [ + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/BoldText" + } + ] + } + }, + "required": [ + "lhs" + ], + "additionalProperties": false, + "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." + }, + "IconText": { + "type": "object", + "properties": { + "icon": { + "$ref": "#/$defs/Icon" + }, + "iconVariant": { + "default": "neutral", + "type": "string", + "enum": [ + "neutral", + "info", + "success", + "warning", + "danger", + "inverted", + "filled", + "soft" + ] + }, + "iconSize": { + "default": "m", + "type": "string", + "enum": [ + "xs", + "s", + "m", + "l", + "xl", + "sm", + "md", + "lg" + ] + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + }, + "layout": { + "default": "horizontal", + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + } + }, + "required": [ + "icon", + "iconVariant", + "iconSize", + "title", + "bold", + "layout" + ], + "additionalProperties": false, + "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." + }, + "ImageText": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + }, + "layout": { + "default": "horizontal", + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + }, + "imageSize": { + "type": "number" + } + }, + "required": [ + "src", + "title", + "bold", + "layout" + ], + "additionalProperties": false, + "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." + }, + "Text": { + "type": "object", + "properties": { + "variant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + }, + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "subtextVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number", + "metric" + ] + }, + "size": { + "default": "sm", + "type": "string", + "enum": [ + "xs", + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "variant", + "value", + "subtextVariant", + "size" + ], + "additionalProperties": false, + "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "BoldText": { + "type": "object", + "properties": { + "variant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + }, + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "subtextVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number", + "metric" + ] + }, + "size": { + "default": "sm", + "type": "string", + "enum": [ + "xs", + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "variant", + "value", + "subtextVariant", + "size" + ], + "additionalProperties": false, + "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "OverviewCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/OverviewCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." + }, + "OverviewCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "top": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + }, + { + "$ref": "#/$defs/Text" + } + ] + }, + "bottom": { + "$ref": "#/$defs/MetricIndicatorInline" + } + }, + "required": [ + "top" + ], + "additionalProperties": false, + "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." + }, + "MetricIndicatorInline": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "trend": { + "type": "object", + "properties": { + "direction": { + "type": "string", + "enum": [ + "up", + "down" + ] + }, + "value": { + "type": "number" + } + }, + "required": [ + "direction", + "value" + ], + "additionalProperties": false + } + }, + "required": [ + "value" + ], + "additionalProperties": false, + "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." + }, + "ContextCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/ContextCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." + }, + "ContextCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/Tag" + } + ] + }, + "body": { + "type": "string" + }, + "bgColor": { + "type": "string", + "enum": [ + "gray" + ] + }, + "bgImageSrc": { + "type": "string" + }, + "bgImageAlt": { + "type": "string" + } + }, + "required": [ + "title" + ], + "additionalProperties": false, + "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." + }, + "Tag": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + }, + "variant": { + "type": "string", + "enum": [ + "neutral", + "info", + "success", + "warning", + "danger" + ] + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Styled tag/badge with optional Icon and variant" + }, + "CompositeCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/CompositeCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." + }, + "CompositeCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "header": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + }, + { + "$ref": "#/$defs/ImageTextLarge" + }, + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/Image" + } + ] + }, + "body": { + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/BoldText" + }, + { + "$ref": "#/$defs/MetricIndicatorInline" + }, + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/ListBlock" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/EntityList" + } + ] + } + }, + "footer": { + "type": "object", + "properties": { + "price": { + "anyOf": [ + { + "$ref": "#/$defs/BoldText" + }, + { + "$ref": "#/$defs/MetricIndicatorWithStrikethrough" + } + ] + }, + "button": { + "$ref": "#/$defs/Button" + } + }, + "additionalProperties": false + } + }, + "required": [ + "body" + ], + "additionalProperties": false, + "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." + }, + "ImageTextLarge": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + } + }, + "required": [ + "src", + "title", + "bold" + ], + "additionalProperties": false, + "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." + }, + "ListBlock": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/ListItem" + } + }, + "variant": { + "type": "string", + "enum": [ + "number", + "image" + ] + }, + "size": { + "type": "string", + "enum": [ + "default", + "small" + ] + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." + }, + "ListItem": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "image": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + } + }, + "required": [ + "src", + "alt" + ], + "additionalProperties": false + }, + "actionLabel": { + "type": "string" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "title" + ], + "additionalProperties": false, + "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." + }, + "MetricIndicatorWithStrikethrough": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "previousValue": { + "type": "string" + }, + "trend": { + "type": "object", + "properties": { + "direction": { + "type": "string", + "enum": [ + "up", + "down" + ] + }, + "value": { + "type": "number" + } + }, + "required": [ + "direction", + "value" + ], + "additionalProperties": false + } + }, + "required": [ + "value" + ], + "additionalProperties": false, + "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." + }, + "VisualCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/VisualCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." + }, + "VisualCardItem": { + "type": "object", + "properties": { + "body": { + "$ref": "#/$defs/BoldText" + }, + "id": { + "type": "string" + }, + "bgImageSrc": { + "type": "string" + }, + "tag": { + "$ref": "#/$defs/Tag" + }, + "bgImageAlt": { + "type": "string" + } + }, + "required": [ + "body" + ], + "additionalProperties": false, + "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." + }, + "FollowUpBlock": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/FollowUpItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "List of clickable follow-up suggestions placed at the end of a response" + }, + "FollowUpItem": { + "type": "object", + "properties": { + "text": { + "type": "string" + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Clickable follow-up suggestion — when clicked, sends text as user message" + }, + "SectionBlock": { + "type": "object", + "properties": { + "sections": { + "type": "array", + "items": { + "$ref": "#/$defs/SectionItem" + } + }, + "isFoldable": { + "type": "boolean" + } + }, + "required": [ + "sections" + ], + "additionalProperties": false, + "description": "Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section." + }, + "SectionItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trigger": { + "type": "string" + }, + "content": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + }, + { + "$ref": "#/$defs/ListBlock" + }, + { + "$ref": "#/$defs/FollowUpBlock" + }, + { + "$ref": "#/$defs/Tabs" + }, + { + "$ref": "#/$defs/Accordion" + } + ] + } + } + }, + "required": [ + "value", + "trigger", + "content" + ], + "additionalProperties": false, + "description": "Section with a label and collapsible content — used inside SectionBlock" + }, + "Tabs": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/TabItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Tabbed container" + }, + "TabItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trigger": { + "type": "string" + }, + "content": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + }, + { + "$ref": "#/$defs/ListBlock" + }, + { + "$ref": "#/$defs/FollowUpBlock" + }, + { + "$ref": "#/$defs/Accordion" + } + ] + } + } + }, + "required": [ + "value", + "trigger", + "content" + ], + "additionalProperties": false, + "description": "value is unique id, trigger is tab label, content is array of components" + }, + "Accordion": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/AccordionItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Collapsible sections" + }, + "AccordionItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trigger": { + "type": "string" + }, + "content": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + }, + { + "$ref": "#/$defs/ListBlock" + }, + { + "$ref": "#/$defs/FollowUpBlock" + } + ] + } + } + }, + "required": [ + "value", + "trigger", + "content" + ], + "additionalProperties": false, + "description": "value is unique id, trigger is section title" + }, + "Carousel": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + }, + { + "$ref": "#/$defs/ListBlock" + }, + { + "$ref": "#/$defs/FollowUpBlock" + } + ] + } + } + }, + "variant": { + "type": "string", + "enum": [ + "card", + "sunk" + ] + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Horizontal scrollable carousel" + }, + "Slice": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "value": { + "type": "number" + } + }, + "required": [ + "category", + "value" + ], + "additionalProperties": false, + "description": "One slice with label and numeric value" + }, + "Label": { + "type": "object", + "properties": { + "text": { + "type": "string" + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Text label" + }, + "SwitchGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/SwitchItem" + } + }, + "variant": { + "type": "string", + "enum": [ + "clear", + "card", + "sunk" + ] + }, + "value": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false, + "description": "Group of switch toggles" + }, + "SwitchItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "defaultChecked": { + "type": "boolean" + } + }, + "required": [ + "name" + ], + "additionalProperties": false, + "description": "Individual switch toggle" + } + } + }, + "root": "Card" + }, + "test": { + "schema": { + "$defs": { + "Card": { + "properties": { + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/Button" + }, + { + "$ref": "#/$defs/Chart" + } + ] + } + }, + "title": { + "type": "string" + } + }, + "required": [ + "children" + ] + }, + "Text": { + "properties": { + "text": { + "type": "string" + }, + "size": { + "type": "string", + "enum": [ + "s", + "m", + "l" + ], + "default": "m" + } + }, + "required": [ + "text" + ] + }, + "Button": { + "properties": { + "label": { + "type": "string" + }, + "action": {}, + "variant": { + "type": "string", + "enum": [ + "primary", + "secondary" + ] + } + }, + "required": [ + "label" + ] + }, + "Input": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "Chart": { + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + }, + "meta": { + "type": "object", + "properties": { + "unit": { + "type": "string" + }, + "scale": { + "type": "number", + "default": 1 + } + }, + "required": [ + "unit" + ] + } + }, + "required": [ + "labels", + "values" + ] + }, + "Tagged": { + "properties": { + "count": { + "type": "integer" + }, + "flag": { + "type": "boolean" + }, + "kind": { + "const": "x" + }, + "tone": { + "type": "string", + "default": "neutral" + } + }, + "required": [ + "tone" + ] + } + } + }, + "root": "Card" + } +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/stream-set.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/stream-set.json new file mode 100644 index 0000000000..308ecef7bd --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/stream-set.json @@ -0,0 +1,669 @@ +[ + { + "name": "basic", + "schema": "test", + "steps": [ + { + "text": "root = Card([t1, b1])\nt1 = ", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [ + "t1", + "b1" + ], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "text": "root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "Hi" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Go" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "b1" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 3, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "text": "root = Card([Text(\"replaced\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "replaced" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + } + ] + }, + { + "name": "missing-required", + "schema": "test", + "steps": [ + { + "text": "root = Card([t1, b1])\nt1 ", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [ + "t1", + "b1" + ], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "text": "root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Go" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "b1" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 3, + "errors": [ + { + "code": "missing-required", + "component": "Text", + "path": "/text", + "message": "missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")", + "statementId": "t1" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "text": "root = Card([Text(\"replaced\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "replaced" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + } + ] + }, + { + "name": "null-required-with-default", + "schema": "test", + "steps": [ + { + "text": "root = Card([t1]", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [] + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": true, + "unresolved": [ + "t1" + ], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "text": "root = Card([t1])\nt1 = Text(null)", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [ + { + "code": "null-required", + "component": "Text", + "path": "/text", + "message": "required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")", + "statementId": "t1" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "text": "root = Card([Text(\"replaced\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "replaced" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + } + ] + }, + { + "name": "required-default-fills", + "schema": "test", + "steps": [ + { + "text": "root = Card([x])\nx = Ta", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [ + "Ta" + ], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "text": "root = Card([x])\nx = Tagged(1, true, \"x\", null)", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Tagged", + "props": { + "count": 1, + "flag": true, + "kind": "x", + "tone": "neutral" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "x" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "text": "root = Card([Text(\"replaced\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "replaced" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + } + ] + }, + { + "name": "unknown-component", + "schema": "test", + "steps": [ + { + "text": "root = Card([Myster", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [] + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": true, + "unresolved": [ + "Myster" + ], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "text": "root = Card([Mystery(\"a\"), Text(\"b\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "b" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [ + { + "code": "unknown-component", + "component": "Mystery", + "path": "", + "message": "Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged", + "statementId": "root" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "text": "root = Card([Text(\"replaced\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "replaced" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + } + ] + }, + { + "name": "excess-args", + "schema": "test", + "steps": [ + { + "text": "root = Card([Text(\"a", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "a" + }, + "partial": true, + "hasDynamicProps": false + } + ] + }, + "partial": true, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": true, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "text": "root = Card([Text(\"a\", \"m\", \"extra\", 4)])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "a", + "size": "m" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [ + { + "code": "excess-args", + "component": "Text", + "path": "", + "message": "Text takes 2 arg(s), got 4 (2 excess dropped)", + "statementId": "root" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "text": "root = Card([Text(\"replaced\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "replaced" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + } + ] + } +] diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json new file mode 100644 index 0000000000..13e2fb3269 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json @@ -0,0 +1 @@ +[{"name":"chat-example-1","schema":"chat","input":"Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }","checkpoints":[{"at":607,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["highlights","statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1214,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1821,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","valu":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ov2","ov3","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":13,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2428,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[],"isFoldable":null},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secLandmarks","secFood","secWhen","f","actionBtns","src1","src2"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3035,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":null,"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["lm1tagIcon","lm2","lm3","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3642,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["lm3body","lm3tag","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":33,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"lm3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["foodCards","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4856,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Sh"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":45,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5463,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"P"},"partial":true,"hasDynamicProps":false,"statementId":"sp2"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sp3","tabSummer","actionBtns","src1","src2"],"orphaned":[],"statementCount":51,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6070,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Sein"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["su2","su3","actionBtns","src1","src2"],"orphaned":[],"statementCount":55,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6677,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":true,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":true,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{}},"partial":true,"hasDynamicProps":false,"statementId":"btn2"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btn3","src1","src2"],"orphaned":[],"statementCount":60,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7277,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":false,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"springList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":false,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":false,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":false,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":false,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{"type":"continue_conversation","context":"Show me the best hotels in Paris"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn2"},{"type":"element","typeName":"Button","props":{"label":"Build a Paris Itinerary","action":{"type":"continue_conversation","context":"Build a 5-day Paris itinerary for me"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn3"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[{"title":"Paris Travel Guide 2025","sourceName":"Travel and Tour World","url":"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/"},{"title":"Best Things to Do in Paris 2026","sourceName":"Time Out Paris","url":"http://www.timeout.fr/paris/en/for-tourists"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-2","schema":"chat","input":"Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")","checkpoints":[{"at":510,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpi1icon","kpi1rhs","kpi2","kpi3","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi1lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1020,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3icon","kpi3rhs","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":13,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi3lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1530,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabGrowth","t","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2040,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["retentio","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2550,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":35,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3060,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tab","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3570,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Sta"]},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":47,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4080,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":null,"body":[]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["supportIcon","supportMetric","supportChart","supportList","cardMarketing","actionButtons"],"orphaned":[],"statementCount":51,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"supportHeader"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4590,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","rig":null}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sup2","sup3","cardMarketing","actionButtons"],"orphaned":[],"statementCount":58,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["marketingMetric","marketingChart","marketingList","actionButtons"],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":true,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":true,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":true,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":true,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Co"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["mkt3","actionButtons"],"orphaned":[],"statementCount":70,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6118,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":false,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":false,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":false,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":false,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Cost per Lead","right":"$48.20","rightVariant":"number"},{"left":"Top Channel","right":"Organic Search","rightVariant":"text"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Break Down by Channel","action":{"type":"continue_conversation","context":"Break down this month's revenue by acquisition channel"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnChannels"},{"type":"element","typeName":"Button","props":{"label":"Forecast Next Quarter","action":{"type":"continue_conversation","context":"Forecast revenue and active users for next quarter"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnForecast"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionButtons"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":74,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-3","schema":"chat","input":"Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)","checkpoints":[{"at":361,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas"},"partial":true,"hasDynamicProps":false,"statementId":"header"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","inspoCards","form"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":722,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["i","insp2","form"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"insp1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1083,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2","form"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1444,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":null,"size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2icon","form"],"orphaned":[],"statementCount":11,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1805,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btnSkip","fcDestination","fcDates","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":15,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2166,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Fo","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":19,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2527,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tr1","tr2","tr3","tr4","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2888,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["oc2","oc3","oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":29,"errors":[{"code":"missing-required","component":"OptionCard","path":"/title","message":"missing required field \"/title\" — signature: OptionCard(value*: string, title*: string, subtitle: string, topContent, disabled: boolean)","statementId":"oc1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":34,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fcNotes"],"orphaned":[],"statementCount":39,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"fcStay"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3971,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":null},"partial":true,"hasDynamicProps":false,"statementId":"ch3"}],"rules":{},"defaultValue":["hotel"]},"partial":true,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":true,"hasDynamicProps":false,"statementId":"fcStay"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ch4","fcNotes"],"orphaned":[],"statementCount":46,"errors":[{"code":"missing-required","component":"Icon","path":"/name","message":"missing required field \"/name\" — signature: Icon(name*: string, category: string)","statementId":"ch3icon"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4322,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":false,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":false,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":{"type":"element","typeName":"Icon","props":{"name":"home","category":"home"},"partial":false,"hasDynamicProps":false,"statementId":"ch3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch3"},{"type":"element","typeName":"ChipItem","props":{"value":"camping","label":"Camping / Glamping","icon":{"type":"element","typeName":"Icon","props":{"name":"tent","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"ch4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch4"}],"rules":{},"defaultValue":["hotel"]},"partial":false,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fcStay"},{"type":"element","typeName":"FormControl","props":{"label":"Special Requests or Notes","input":{"type":"element","typeName":"TextArea","props":{"name":"special-requests","placeholder":"e.g. vegetarian meals, wheelchair access, honeymoon surprise...","rows":4},"partial":false,"hasDynamicProps":false,"statementId":"notesArea"},"hint":"Any dietary needs, accessibility requirements, or specific interests?"},"partial":false,"hasDynamicProps":false,"statementId":"fcNotes"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":50,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-4","schema":"chat","input":"Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }","checkpoints":[{"at":218,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Ene"},"partial":true,"hasDynamicProps":false,"statementId":"header"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":436,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to w"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":654,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["v1body","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"v1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":872,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":null,"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v1icon","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1090,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":null,"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v2tag","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1308,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["CompositeCard","src1","src2"],"orphaned":[],"statementCount":14,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1526,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1icon","t1body","t1tags","t1btn","t2","src1","src2"],"orphaned":[],"statementCount":16,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t1h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1744,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Wa"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2","src1","src2"],"orphaned":[],"statementCount":20,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1962,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2icon","t2body","t2tags","t2btn","src1","src2"],"orphaned":[],"statementCount":22,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t2h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":[]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2btn","src1","src2"],"orphaned":[],"statementCount":25,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2398,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceN":null}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2615,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":false,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":false,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},{"title":"Sajan Re (Official Music Video)","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=COUSCnFazzc"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-5","schema":"chat","input":"Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")","checkpoints":[{"at":37,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":74,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["title","tbl","followUps"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":111,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":""},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tbl","followUps"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":148,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":185,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs","users","followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":222,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Pyth"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years","followUps"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":259,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["years","followUps"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":296,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":333,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu1"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":370,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me m"},"partial":true,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu2"],"orphaned":[],"statementCount":8,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":407,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["FollowUpItem"],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":442,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"},{"type":"element","typeName":"FollowUpItem","props":{"text":"Show me a JavaScript comparison"},"partial":false,"hasDynamicProps":false,"statementId":"fu2"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"basic","schema":"test","input":"root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Bu"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Button","path":"/label","message":"missing required field \"/label\" — signature: Button(label*: string, action, variant: \"primary\"|\"secondary\")","statementId":"b1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-required","schema":"test","input":"root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["B"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Button"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":51,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"null-required-with-default","schema":"test","input":"root = Card([t1])\nt1 = Text(null)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"required-default-fills","schema":"test","input":"root = Card([x])\nx = Tagged(1, true, \"x\", null)","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tag"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":null,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-component","schema":"test","input":"root = Card([Mystery(\"a\"), Text(\"b\")])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mys"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mystery"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"excess-args","schema":"test","input":"root = Card([Text(\"a\", \"m\", \"extra\", 4)])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":41,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"type-mismatch-scalar","schema":"test","input":"root = Card([Text(42)], 7)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/title","message":"field \"/title\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-mismatch","schema":"test","input":"root = Card([Text(\"a\", \"xl\"), Button(\"b\", null, \"tertiary\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Button"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"terti"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"tertiary"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/size","message":"field \"/size\" expects one of [\"s\", \"m\", \"l\"] but got \"xl\"","statementId":"root"},{"code":"type-mismatch","component":"Button","path":"/variant","message":"field \"/variant\" expects one of [\"primary\", \"secondary\"] but got \"tertiary\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-partial-deferred","schema":"test","input":"root = Card([Text(\"a\", \"x","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"integer-boolean-const","schema":"test","input":"root = Card([x])\nx = Tagged(1.5, \"yes\", \"y\", \"loud\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tagg"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":{"k":"Member","obj":{"k":"Num","v":1},"field":"?"},"tone":"neutral"},"partial":true,"hasDynamicProps":true,"statementId":"x"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"loud"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"loud"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"},{"code":"type-mismatch","component":"Tagged","path":"/kind","message":"field \"/kind\" expects one of [\"x\"] but got \"y\"","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"nested-object","schema":"test","input":"root = Card([c1, c2, c3])\nc1 = Chart([\"a\"], [1], {unit: \"kg\"})\nc2 = Chart([\"a\"], [1], {scale: 2})\nc3 = Chart([\"a\"], [1], {unit: 5, scale: \"big\"})","checkpoints":[{"at":13,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c1","c2","c3"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"un":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":65,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":78,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":91,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scal":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c2"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":104,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":117,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":130,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":143,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":145,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c3"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"},{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"array-items-pruned","schema":"test","input":"root = Card([Chart([\"a\", 2, \"c\"], [1, \"x\", 3])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"element-in-data-slot","schema":"test","input":"root = Card([Chart([Text(\"a\")], [1])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unresolved-and-orphaned","schema":"test","input":"root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a","miss"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":58,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cycle","schema":"test","input":"root = Card([a])\na = Card([b])\nb = Card([a])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"b"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"self-reference","schema":"test","input":"root = Card([root])","checkpoints":[{"at":2,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["r"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["roo"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"no-root-first-component","schema":"test","input":"x = 1\nmain = Card([Text(\"a\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["main"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"main"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"root-name-statement","schema":"test","input":"Card = Card([Text(\"named\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"Card"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"n"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"duplicate-ids","schema":"test","input":"root = Card([a])\na = Text(\"first\")\na = Text(\"second\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fir"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":53,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"only-prose","schema":"test","input":"Here is your UI, it will appear below.","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"whitespace","schema":"test","input":" \n\t \n","checkpoints":[{"at":1,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fences-and-prose","schema":"test","input":"Sure! Here it is:\n```openui\nroot = Card([a])\na = Text(\"fenced\")\n```\nAnything else?","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"f"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":82,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiple-fences","schema":"test","input":"```\nroot = Card([a])\n```\nand\n```\na = Text(\"second block\")\n```","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"secon"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second bloc"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unclosed-fence","schema":"test","input":"```openui\nroot = Card([a])\na = Text(\"str","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"str"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fence-in-string","schema":"test","input":"root = Card([a])\na = Text(\"use ``` to fence\")","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"u"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use `"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` t"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fe"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"comments","schema":"test","input":"root = Card([a]) // trailing\n# full line\na = Text(\"not // a comment # here\")\n// done","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not /"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a com"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment #"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"crlf","schema":"test","input":"root = Card([a])\r\na = Text(\"windows\")\r\n","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"wind"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"string-escapes","schema":"test","input":"root = Card([a, b, c, d])\na = Text(\"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83d\\ude00\")\nb = Text('single \\' quote \\n esc \\q')\nc = Text(\"bad \\x escape\")\nd = Text(\"emoji 😀 and é and 漢字\")","checkpoints":[{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nqu"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ uni"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":112,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' qu"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":128,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x"},"partial":true,"hasDynamicProps":false,"statementId":"c"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["d"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":160,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":176,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":true,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and"},"partial":true,"hasDynamicProps":false,"statementId":"d"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":187,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and é and 漢字"},"partial":false,"hasDynamicProps":false,"statementId":"d"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"emoji-outside-strings","schema":"test","input":"root = Card([a]) 😀\na = Text(\"ok\") ✅","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-string","schema":"test","input":"root = Card([a])\na = Text(\"streaming tex","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"s"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"strea"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming tex"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-escape","schema":"test","input":"root = Card([a])\na = Text(\"ends with \\","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with \\"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"numbers","schema":"test","input":"root = Card([Chart([\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"], [-3, 1.5, 1e3, 007, -0, 2.5e-3])])\n$x = 1e\n$y = 1E+2\n$z = 3.","checkpoints":[{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Chart"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,0]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,{"k":"Member","obj":{"k":"Num","v":2},"field":"?"},null]},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":81,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$x":null},"queryStatements":[],"mutationStatements":[]}},{"at":99,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$x":null,"$y":100},"queryStatements":[],"mutationStatements":[]}},{"at":106,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$x":null,"$y":100,"$z":{"k":"Member","obj":{"k":"Num","v":3},"field":"?"}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"operators","schema":"test","input":"$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])","checkpoints":[{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$a":1},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":""}}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"ye"},"else":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":88,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":92,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiline-ternary","schema":"test","input":"$on = true\nroot = Card([t])\nt = Text($on\n ? \"enabled\"\n : \"disabled\")","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"StateRef","n":"$on"}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"en"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabl"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabled"}}},"partial":false,"hasDynamicProps":true,"statementId":"t"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}}]},{"name":"member-index","schema":"test","input":"$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"row":null}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":""}]}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":null,"?":null}]}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key":null}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"row"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":139,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key x"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"builtins","schema":"test","input":"$items = [3, 1, 2]\nroot = Card([Text(\"\" + @Count($items)), Text(\"\" + @Sum($items)), Text(@Round(2.555, 2) + \"\")])\nbare = Count($items)","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3]},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Count"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Count"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Su"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Su"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Comp","name":"Round","args":[]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":134,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"actions","schema":"test","input":"$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))","checkpoints":[{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Card"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1","b2","b3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Ac","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Ph","n":"ToAssistant"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ToAssistant","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":126,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Ph","n":"Res"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Res","b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":162,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["But"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Action"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":198,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https:"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":215,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https://openui.com"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b3"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}}]},{"name":"each","schema":"test","input":"$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))","checkpoints":[{"at":10,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[]},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a"}]},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["f","f"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"ti":null,"?":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b"}]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["Each"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ph","n":"t"}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[],"mappedProps":{}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":110,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":113,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"query-mutation","schema":"test","input":"$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])","checkpoints":[{"at":19,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["users"],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":57,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"Null"}],["?",{"k":"Null"}]]},"defaultsAST":null,"refreshAST":null,"deps":["$q"],"complete":true}],"mutationStatements":[]}},{"at":76,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":null,"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":95,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["save"],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":114,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"Null"}],["?",{"k":"Null"}]]}}]}},{"at":133,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":152,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"le"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":171,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["B"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":190,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Actio"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":209,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Ph","n":"Run"}]}]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Run"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":221,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"users","refType":"query"}]}]}]}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}}]},{"name":"state-query","schema":"test","input":"$data = Query(\"get\", {})\nroot = Card([Text(\"x\")])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Qu","Qu"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":null},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":""},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":25,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}}]},{"name":"inline-query","schema":"test","input":"root = Card([Text(Query(\"get\", {}))])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Qu"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":37,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"assignment","schema":"test","input":"$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Inpu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"na"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"excess-args","component":"Input","path":"","message":"Input takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$valu"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$valu":null},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$value"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$value":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"object-key-order","schema":"test","input":"$o = {b: 1, 2: \"two\", a: 3, 1: \"one\", \"10\": 10}\nroot = Card([Text(\"x\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{}},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"tw","b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"two","b":1,"a":null}},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":null,"2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":null,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-commas","schema":"test","input":"root = Card([Text(\"a\") Text(\"b\"), Text(\"c\"),])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":46,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"lowercase-builtin-name","schema":"test","input":"root = Card([Text(@first([1]))])","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fi"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["first"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-tokens","schema":"test","input":"root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"combining-characters","schema":"test","input":"root = Card([Text(\"e\\u0301 cafe\\u0301\"), Text(\"한국어\"), Text(\"ok\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u03"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é caf"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u0301 cafe\\u030"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-call","schema":"test","input":"root = Card([a, b])\na = Text(\"one\")\nb = Button(\"tw","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","b"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Butto"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Button","props":{"label":"tw"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-object","schema":"test","input":"root = Card([Chart([\"a\"], [1], {unit: \"k","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":null,"?":null}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"k"}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}] diff --git a/packages/swift-lang/Tests/OpenUILangTests/JSSemanticsTests.swift b/packages/swift-lang/Tests/OpenUILangTests/JSSemanticsTests.swift new file mode 100644 index 0000000000..1a72658fcd --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/JSSemanticsTests.swift @@ -0,0 +1,64 @@ +import Testing + +@testable import OpenUILang + +/// Expected values were produced by Node.js, so these pin the port to real +/// JavaScript behaviour rather than to what Swift does by default. +@Suite struct JSSemanticsTests { + @Test(arguments: [ + (0.0, "0"), (-0.0, "0"), (1, "1"), (-1, "-1"), (0.1 + 0.2, "0.30000000000000004"), + (100, "100"), (1e21, "1e+21"), (1e-7, "1e-7"), (1.5e-7, "1.5e-7"), (123e-20, "1.23e-18"), + (1e20, "100000000000000000000"), (123_456_789_012_345_680_000, "123456789012345680000"), + (0.000001, "0.000001"), (5e-324, "5e-324"), + (1.797_693_134_862_315_7e308, "1.7976931348623157e+308"), (.nan, "NaN"), + (.infinity, "Infinity"), (-.infinity, "-Infinity"), (2.5, "2.5"), (-2.5e-3, "-0.0025"), + (1.0 / 3, "0.3333333333333333"), + ]) + func numberToString(_ value: Double, _ expected: String) { + #expect(jsNumberToString(value) == expected) + } + + @Test(arguments: [ + (" 12 ", 12.0), ("0x1F", 31), ("0b101", 5), ("0o17", 15), ("", 0), (" ", 0), (".5", 0.5), + ("5.", 5), ("Infinity", .infinity), ("-Infinity", -.infinity), ("+3", 3), ("1e+2", 100), + ("1E-2", 0.01), ("\u{00A0}12\u{FEFF}", 12), + ]) + func stringToNumber(_ text: String, _ expected: Double) { + #expect(jsStringToNumber(text) == expected) + } + + @Test(arguments: ["1e", "1_000", "12px", "-0x1F", "--1", "0.0.1"]) + func stringToNumberNaN(_ text: String) { + #expect(jsStringToNumber(text).isNaN) + } + + @Test func looseEquality() { + let pairs: [(OpenUIValue, OpenUIValue, Bool)] = [ + (1, "1", true), ("1", 1, true), (0, "", true), (0, "0", true), ("", 0, true), + (.null, .undefined, true), (.null, 0, false), (.undefined, 0, false), (true, 1, true), + (true, "1", true), (false, "", true), ("true", true, false), ([1], 1, true), + ([1, 2], "1,2", true), (["a": 1], "[object Object]", true), + (.number(.nan), .number(.nan), false), + ("a", "a", true), ([], "", true), ([.null], "", true), (2, true, false), + ] + for (a, b, expected) in pairs { + #expect(a.looselyEquals(b) == expected, "\(a) == \(b)") + } + } + + @Test func truthiness() { + let falsy: [OpenUIValue] = [.undefined, .null, false, 0, -0.0, .number(.nan), ""] + let truthy: [OpenUIValue] = [true, 1, -1, "0", " ", [], [:]] + for value in falsy { #expect(!value.isTruthy, "\(value)") } + for value in truthy { #expect(value.isTruthy, "\(value)") } + } + + @Test func objectKeyOrder() { + var object = OpenUIObject() + for key in ["b", "2", "a", "1", "10", "01"] { object[key] = .string(key) } + // Integer-like keys first in ascending order, then insertion order ("01" is not canonical). + #expect(object.keys == ["1", "2", "10", "b", "a", "01"]) + object["2"] = nil + #expect(object.keys == ["1", "10", "b", "a", "01"]) + } +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/ParserConformanceTests.swift b/packages/swift-lang/Tests/OpenUILangTests/ParserConformanceTests.swift new file mode 100644 index 0000000000..f754449276 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/ParserConformanceTests.swift @@ -0,0 +1,47 @@ +import Testing + +@testable import OpenUILang + +/// The Swift parser must produce exactly what lang-core produces for the same input. +@Suite struct ParserConformanceTests { + @Test(arguments: FixtureCase.all("parser")) + func parse(_ fixture: FixtureCase) { + let schema = fixture.value["schema"].stringValue! + let result = OpenUILang.parse( + fixture.value["input"].stringValue!, Fixtures.paramMap(schema), + rootName: Fixtures.rootName(schema)) + let diff = firstDifference( + normalized(result.jsonRepresentation), normalized(fixture.value["expected"])) + #expect(diff == nil, "\(fixture.name): \(diff ?? "")") + } + + @Test(arguments: FixtureCase.all("streaming")) + func streamingPush(_ fixture: FixtureCase) { + let schema = fixture.value["schema"].stringValue! + let input = Array(fixture.value["input"].stringValue!.utf16) + let parser = StreamParser(Fixtures.paramMap(schema), rootName: Fixtures.rootName(schema)) + var last = 0 + for checkpoint in fixture.value["checkpoints"].arrayValue ?? [] { + let at = Int(checkpoint["at"].numberValue!) + let chunk = String(decoding: input[last.. Date: Mon, 5 Oct 2026 03:35:02 +0530 Subject: [PATCH 02/52] feat(swift-lang): add evaluator, store, actions and queries Ports the runtime half of lang-core and react-lang's useOpenUIState to OpenUILang: - the expression evaluator (operators, builtins, @Each, action steps, reactive assignments) and schema-aware prop evaluation - the state store, state fields and form rule validators - the query manager (caching, refresh intervals, mutations, MCP results) behind a ToolProvider protocol - OpenUIRuntime, which ties the streaming parser, store, evaluation, form fields and action execution together for UI layers to observe Evaluation fixtures generated from lang-core cover operators, builtins, action plans, ternary components, bindings, query results and every chat library example. One intentional difference: lang-core re-evaluates the binding of a reactive input rendered inside @Each or a ternary, nesting it four levels deep, so typing writes undefined into the bound $state. The Swift port keeps the binding intact; RuntimeTests pins the expected behaviour. --- .../swift-lang/Scripts/generate-fixtures.mjs | 110 +- .../Sources/OpenUILang/EvaluateTree.swift | 82 + .../Sources/OpenUILang/Evaluator.swift | 346 ++ .../Sources/OpenUILang/FormRules.swift | 203 + .../Sources/OpenUILang/QueryManager.swift | 475 +++ .../Sources/OpenUILang/Runtime.swift | 251 ++ .../swift-lang/Sources/OpenUILang/Store.swift | 94 + .../swift-lang/Sources/OpenUILang/Value.swift | 6 + .../EvaluationConformanceTests.swift | 41 + .../OpenUILangTests/Fixtures/evaluation.json | 3562 +++++++++++++++++ .../OpenUILangTests/Fixtures/schemas.json | 38 +- .../OpenUILangTests/QueryAndFormTests.swift | 134 + .../Tests/OpenUILangTests/RuntimeTests.swift | 167 + 13 files changed, 5505 insertions(+), 4 deletions(-) create mode 100644 packages/swift-lang/Sources/OpenUILang/EvaluateTree.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Evaluator.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/FormRules.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/QueryManager.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Runtime.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Store.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/EvaluationConformanceTests.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/Fixtures/evaluation.json create mode 100644 packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/RuntimeTests.swift diff --git a/packages/swift-lang/Scripts/generate-fixtures.mjs b/packages/swift-lang/Scripts/generate-fixtures.mjs index eeb1c9c208..1897f71bd1 100644 --- a/packages/swift-lang/Scripts/generate-fixtures.mjs +++ b/packages/swift-lang/Scripts/generate-fixtures.mjs @@ -82,7 +82,45 @@ const testSchema = { }, }; -const schemas = { chat: { schema: chatSchema, root: "Card" }, test: { schema: testSchema, root: "Card" } }; +/** Props bound two-way to $state (lang-core's reactive()), per component. */ +function reactiveProps(library) { + const out = {}; + for (const [name, comp] of Object.entries(library.components)) { + const keys = Object.entries(comp.props.shape ?? {}) + .filter(([, schema]) => core.isReactiveSchema(schema)) + .map(([key]) => key); + if (keys.length) out[name] = keys; + } + return out; +} + +// The test schema has no Zod library behind it, so build the minimal shape +// evaluateElementProps reads: components[name].props.shape[prop]. +const testReactive = { Input: ["value"] }; +const testLibrary = { + components: Object.fromEntries( + Object.entries(testSchema.$defs).map(([name, def]) => [ + name, + { + props: { + shape: Object.fromEntries( + Object.keys(def.properties).map((key) => { + const schema = {}; + if (testReactive[name]?.includes(key)) core.markReactive(schema); + return [key, schema]; + }), + ), + }, + }, + ]), + ), +}; + +const schemas = { + chat: { schema: chatSchema, root: "Card", reactive: reactiveProps(ui.openuiChatLibrary) }, + test: { schema: testSchema, root: "Card", reactive: testReactive }, +}; +const libraries = { chat: ui.openuiChatLibrary, test: testLibrary }; // ── Corpus ──────────────────────────────────────────────────────────────── @@ -242,6 +280,73 @@ const setCases = edgeCases.slice(0, 6).map((c) => { return { name: c.name, schema: c.schema, steps }; }); +// ── Evaluation ────────────────────────────────────────────────────────── + +const unwrap = (v) => + v && typeof v === "object" && !Array.isArray(v) && "value" in v ? v.value : v; + +/** Parses, seeds a store like the renderer does, and evaluates the tree. */ +function evaluateCase(c) { + const result = parseWith(c.schema, c.input); + const store = core.createStore(); + store.initialize(result.stateDeclarations, {}); + for (const [key, value] of Object.entries(c.state ?? {})) store.set(key, value); + const ctx = { + getState: (name) => unwrap(store.get(name)), + resolveRef: (name) => (c.queryResults ?? {})[name] ?? null, + }; + const errors = []; + const root = result.root + ? core.evaluateElementProps(result.root, { ctx, library: libraries[c.schema], store, errors }) + : null; + return { root, errors }; +} + +const e = (name, input, extra = {}) => ({ name, schema: "test", input, ...extra }); + +const evalCases = [ + ...chatExamples, + e("operators", edgeCases.find((c) => c.name === "operators").input), + e("member-index", edgeCases.find((c) => c.name === "member-index").input), + e("actions", edgeCases.find((c) => c.name === "actions").input), + e("each", edgeCases.find((c) => c.name === "each").input), + e( + "builtins-all", + '$n = [5, "3", 9, "x", true]\n$rows = [{n: "b", v: 2}, {n: "a", v: 10}, {n: "c", v: "1"}]\nroot = Card([Text("" + @Count($n) + "|" + @Sum($n) + "|" + @Avg($n) + "|" + @Min($n) + "|" + @Max($n) + "|" + @First($n) + "|" + @Last($n) + "|" + @Round(-2.5) + "|" + @Round(1.005, 2) + "|" + @Abs(-3) + "|" + @Floor(1.7) + "|" + @Ceil(1.2)), Text(@Sort($rows, "v", "desc").n + ""), Text(@Sort($rows, "n").n + ""), Text(@Filter($rows, "v", ">", 1).n + ""), Text(@Filter($rows, "n", "contains", "a").n + ""), Text(@Filter($rows, "v", "==", "2").n + "")])', + ), + e( + "arithmetic-edges", + '$z = 0\nroot = Card([Text("" + (5 / $z) + "|" + (-7 % 3) + "|" + (7 % $z) + "|" + ("a" + null) + "|" + (null + 1) + "|" + (true + 1) + "|" + ("5" * "2") + "|" + ("x" - 1) + "|" + (0.1 + 0.2) + "|" + (1 / 3))])', + ), + e( + "truthiness-and-equality", + '$e = ""\n$z = 0\n$arr = []\nroot = Card([Text("" + ($e || "empty") + "|" + ($z && "no") + "|" + ($arr ? "arr-truthy" : "arr-falsy") + "|" + (1 == "1") + "|" + (null == 0) + "|" + ($missing == null) + "|" + !$e)])', + ), + e( + "ternary-components", + '$on = true\nroot = Card([$on ? Text("on", "l") : Button("off"), $on ? null : Text("hidden")])', + ), + e( + "ternary-components-off", + '$on = true\nroot = Card([$on ? Text("on", "l") : Button("off")])', + { state: { $on: false } }, + ), + e("state-override", '$count = 1\nroot = Card([Text("count " + $count)])', { state: { $count: 41 } }), + e("reactive-binding", '$v = "hi"\nroot = Card([Input("name", $v), Input("plain", "x")])'), + e("reactive-assign", '$v = ""\nroot = Card([Input("name", $v = $value)])'), + e( + "query-results", + edgeCases.find((c) => c.name === "query-mutation").input, + { queryResults: { users: { rows: [{ id: 1 }, { id: 2 }] }, save: { status: "idle" } } }, + ), + e( + "each-actions", + '$items = [{id: 1, t: "a"}, {id: 2, t: "b"}]\n$sel = 0\nroot = Card(@Each($items, it, Button(it.t, Action([@Set($sel, it.id), @ToAssistant("Pick " + it.t)]))))', + ), +]; + +const evalFixtures = evalCases.map((c) => ({ ...c, expected: evaluateCase(c) })); + function write(name, data, indent = 1) { mkdirSync(fixtures, { recursive: true }); writeFileSync(join(fixtures, name), JSON.stringify(data, null, indent) + "\n"); @@ -251,7 +356,8 @@ write("schemas.json", Object.fromEntries(Object.entries(schemas))); write("parser.json", parserCases); write("streaming.json", streamingCases, 0); write("stream-set.json", setCases); +write("evaluation.json", evalFixtures); console.log( - `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set fixtures`, + `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set, ${evalFixtures.length} evaluation fixtures`, ); diff --git a/packages/swift-lang/Sources/OpenUILang/EvaluateTree.swift b/packages/swift-lang/Sources/OpenUILang/EvaluateTree.swift new file mode 100644 index 0000000000..112e58d541 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/EvaluateTree.swift @@ -0,0 +1,82 @@ +/// Evaluates one prop value with schema awareness: AST nodes, reactive +/// bindings, nested elements, arrays and action plans. The inline and tree +/// paths differ only in how they recurse, so they pass that in. +func evaluatePropCore( + _ value: OpenUIValue, _ context: EvaluationContext, _ schema: SchemaContext, reactive: Bool, + recurseElement: (ElementNode) -> ElementNode, + recurse: (OpenUIValue, Bool) -> OpenUIValue +) -> OpenUIValue { + switch value { + case .undefined, .null, .bool, .number, .string: + return value + + case .ast(let node): + // A $state on a reactive prop becomes a two-way binding. + if case .stateRef(let name) = node, reactive { + return .reactiveAssign(ReactiveAssign(target: name, expr: .stateRef("$value"))) + } + let result = evaluate(node, context, schema) + switch result { + case .element(let element): + return .element(recurseElement(element)) + case .array(let items): + return .array( + items.map { item in + if case .element(let element) = item { return .element(recurseElement(element)) } + return item + }) + case .reactiveAssign(let assign) where !reactive: + let current = context.getState(assign.target) + return current.isNullish ? .null : current + default: + return result + } + + case .array(let items): + return .array(items.map { recurse($0, reactive) }) + + case .element(let element): + return .element(recurseElement(element)) + + case .actionPlan, .actionStep, .reactiveAssign: + // Evaluated when the action fires or the field is set, not now. + return value + + case .object(let object): + let needsEval = object.values.contains { member in + switch member { + case .undefined, .null, .bool, .number, .string: return false + default: return true + } + } + guard needsEval else { return value } + var result = OpenUIObject() + for (key, member) in object { result[key] = recurse(member, reactive) } + return .object(result) + } +} + +/// Evaluates every AST node in an element's props (recursively), returning an +/// element whose props are concrete values ready to render. +public func evaluateElementProps( + _ element: ElementNode, _ context: EvaluationContext, _ schema: SchemaContext +) -> ElementNode { + if element.hasDynamicProps == false { return element } + var evaluated = OpenUIObject() + for (key, value) in element.props { + evaluated[key] = evaluatePropValue( + value, context, schema, reactive: schema.isReactiveProp(element.typeName, key)) + } + var result = element + result.props = evaluated + return result +} + +private func evaluatePropValue( + _ value: OpenUIValue, _ context: EvaluationContext, _ schema: SchemaContext, reactive: Bool +) -> OpenUIValue { + evaluatePropCore( + value, context, schema, reactive: reactive, + recurseElement: { evaluateElementProps($0, context, schema) }, + recurse: { evaluatePropValue($0, context, schema, reactive: $1) }) +} diff --git a/packages/swift-lang/Sources/OpenUILang/Evaluator.swift b/packages/swift-lang/Sources/OpenUILang/Evaluator.swift new file mode 100644 index 0000000000..4e998a835f --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Evaluator.swift @@ -0,0 +1,346 @@ +/// Supplies `$state` values and statement references to the evaluator. +public struct EvaluationContext { + /// Reads a `$variable` from the store. + public var getState: (String) -> OpenUIValue + /// Resolves a reference to another declaration's value (Query/Mutation results). + public var resolveRef: (String) -> OpenUIValue + /// Extra scope for `$value` while applying a reactive assignment. + public var extraScope: OpenUIObject? + + public init( + getState: @escaping (String) -> OpenUIValue, + resolveRef: @escaping (String) -> OpenUIValue = { _ in .undefined }, + extraScope: OpenUIObject? = nil + ) { + self.getState = getState + self.resolveRef = resolveRef + self.extraScope = extraScope + } +} + +/// Library knowledge the evaluator needs: which component props bind to +/// `$state` two-way (lang-core's `reactive()` schemas). +public struct SchemaContext { + public var isReactiveProp: (_ component: String, _ prop: String) -> Bool + + public init(isReactiveProp: @escaping (String, String) -> Bool) { + self.isReactiveProp = isReactiveProp + } +} + +/// Evaluates an AST node to a runtime value. +public func evaluate( + _ node: ASTNode, _ context: EvaluationContext, _ schema: SchemaContext? = nil +) -> OpenUIValue { + switch node { + case .str(let value): return .string(value) + case .num(let value): return .number(value) + case .bool(let value): return .bool(value) + case .null, .ph: return .null + + case .stateRef(let name): + if let scoped = context.extraScope?[name], !scoped.isNullish { return scoped } + return context.getState(name) + + case .ref(let name), .runtimeRef(let name, _): + return context.resolveRef(name) + + case .arr(let elements): + return .array(elements.map { evaluate($0, context) }) + + case .obj(let entries): + var object = OpenUIObject() + for entry in entries { object[entry.key] = evaluate(entry.value, context) } + return .object(object) + + case .comp(let name, let args, let mappedProps): + if lazyBuiltins.contains(name) { return evaluateLazyBuiltin(name, args, context, schema) } + if let builtin = builtins[name] { return builtin.fn(args.map { evaluate($0, context) }) } + if actionNames.contains(name) { return evaluateActionCall(name, args, context) } + if let mappedProps { return evaluateMappedComponent(name, mappedProps, context, schema) } + // Every catalog component is lowered to an element at parse time, so an + // unmapped call here is unexpected. + return .null + + case .binOp(let op, let left, let right): + return evaluateBinary(op, left, right, context) + + case .unaryOp(let op, let operand): + switch op { + case "!": return .bool(!evaluate(operand, context).isTruthy) + case "-": return .number(-toNumber(evaluate(operand, context))) + default: return .null + } + + case .ternary(let cond, let then, let otherwise): + return evaluate(cond, context).isTruthy ? evaluate(then, context) : evaluate(otherwise, context) + + case .member(let objNode, let field): + let obj = evaluate(objNode, context) + if obj.isNullish { return .null } + // Array pluck: `rows.name` maps over the items. + if case .array(let items) = obj { + if field == "length" { return .number(Double(items.count)) } + return .array( + items.map { item in + if item.isNullish { return .null } + let value = jsProperty(item, field) + return value.isNullish ? .null : value + }) + } + return jsProperty(obj, field) + + case .index(let objNode, let indexNode): + let obj = evaluate(objNode, context) + let index = evaluate(indexNode, context) + if obj.isNullish || index.isNullish { return .null } + if case .array = obj { return jsProperty(obj, jsNumberToString(toNumber(index))) } + return jsProperty(obj, index.jsString) + + case .assign(let target, let value): + return .reactiveAssign(ReactiveAssign(target: target, expr: value)) + } +} + +private func evaluateBinary( + _ op: String, _ leftNode: ASTNode, _ rightNode: ASTNode, _ context: EvaluationContext +) -> OpenUIValue { + // Short-circuit operators return an operand, like JavaScript. + if op == "&&" { + let left = evaluate(leftNode, context) + return left.isTruthy ? evaluate(rightNode, context) : left + } + if op == "||" { + let left = evaluate(leftNode, context) + return left.isTruthy ? left : evaluate(rightNode, context) + } + let left = evaluate(leftNode, context) + let right = evaluate(rightNode, context) + switch op { + case "+": + if left.jsTypeof == "string" || right.jsTypeof == "string" { + // null/undefined concatenate as "" rather than "null". + let l = left.isNullish ? "" : left.jsString + let r = right.isNullish ? "" : right.jsString + return .string(l + r) + } + return .number(toNumber(left) + toNumber(right)) + case "-": return .number(toNumber(left) - toNumber(right)) + case "*": return .number(toNumber(left) * toNumber(right)) + case "/": + // Division by zero is 0, a deliberate DSL choice over Infinity/NaN. + return .number(toNumber(right) == 0 ? 0 : toNumber(left) / toNumber(right)) + case "%": + return .number( + toNumber(right) == 0 ? 0 : toNumber(left).truncatingRemainder(dividingBy: toNumber(right))) + case "==": return .bool(left.looselyEquals(right)) + case "!=": return .bool(!left.looselyEquals(right)) + case ">": return .bool(toNumber(left) > toNumber(right)) + case "<": return .bool(toNumber(left) < toNumber(right)) + case ">=": return .bool(toNumber(left) >= toNumber(right)) + case "<=": return .bool(toNumber(left) <= toNumber(right)) + default: return .null + } +} + +/// A catalog component inside a runtime expression (a ternary branch, an +/// `@Each` template): builds its element from the mapped props. +private func evaluateMappedComponent( + _ name: String, _ mappedProps: [ASTEntry], _ context: EvaluationContext, + _ schema: SchemaContext? +) -> OpenUIValue { + var props = OpenUIObject() + for entry in mappedProps { + if case .stateRef(let stateName) = entry.value { + if let schema, schema.isReactiveProp(name, entry.key) { + // Reactive prop bound to $state: emit a two-way binding. + props[entry.key] = .reactiveAssign( + ReactiveAssign(target: stateName, expr: .stateRef("$value"))) + } else { + // Without schema context the StateRef stays AST for evaluateElementProps. + props[entry.key] = schema != nil ? context.getState(stateName) : .ast(entry.value) + } + } else { + props[entry.key] = evaluate(entry.value, context, schema) + } + } + if let schema { + for (key, value) in props { + switch value { + case .element(let element): + props[key] = .element(evaluateElementInline(element, context, schema)) + case .array(let items): + props[key] = .array( + items.map { item in + if case .element(let element) = item { + return .element(evaluateElementInline(element, context, schema)) + } + return item + }) + default: + break + } + } + } + return .element(ElementNode(typeName: name, props: props, partial: false, hasDynamicProps: true)) +} + +/// Resolves a reactive assignment to the current state value outside a reactive prop. +public func stripReactiveAssign(_ value: OpenUIValue, _ context: EvaluationContext) -> OpenUIValue { + guard case .reactiveAssign(let assign) = value else { return value } + let current = context.getState(assign.target) + return current.isNullish ? .null : current +} + +/// Evaluates an element's props with schema awareness (inline path). +func evaluateElementInline( + _ element: ElementNode, _ context: EvaluationContext, _ schema: SchemaContext +) -> ElementNode { + if element.hasDynamicProps == false { return element } + var evaluated = OpenUIObject() + for (key, value) in element.props { + evaluated[key] = evaluatePropInline( + value, context, schema, reactive: schema.isReactiveProp(element.typeName, key)) + } + var result = element + result.props = evaluated + return result +} + +private func evaluatePropInline( + _ value: OpenUIValue, _ context: EvaluationContext, _ schema: SchemaContext, reactive: Bool +) -> OpenUIValue { + evaluatePropCore( + value, context, schema, reactive: reactive, + recurseElement: { evaluateElementInline($0, context, schema) }, + recurse: { evaluatePropInline($0, context, schema, reactive: $1) }) +} + +/// Converts a runtime value back to a literal AST node so it can be captured in +/// a deferred expression (an action evaluated at click time). +func toLiteralAST(_ value: OpenUIValue) -> ASTNode { + switch value { + case .undefined, .null: return .null + case .string(let string): return .str(string) + case .number(let number): return .num(number) + case .bool(let bool): return .bool(bool) + case .array(let items): return .arr(items.map(toLiteralAST)) + case .object(let object): + return .obj(object.entries.map { ASTEntry($0.key, toLiteralAST($0.value)) }) + default: + // Elements, AST and action markers are plain objects in JavaScript. + return toLiteralAST(value.jsonRepresentation) + } +} + +/// `Action`, `Run`, `ToAssistant`, `OpenUrl`, `Set` and `Reset` calls. +private func evaluateActionCall(_ name: String, _ args: [ASTNode], _ context: EvaluationContext) + -> OpenUIValue +{ + func stringArg(_ index: Int) -> String { + let value = evaluate(args[index], context) + return value.isNullish ? "" : value.jsString + } + switch name { + case "Action": + let stepsValue = args.isEmpty ? .array([]) : evaluate(args[0], context) + let steps: [ActionStep] = (stepsValue.arrayValue ?? []).compactMap { + if case .actionStep(let step) = $0 { return step } + return nil + } + return .actionPlan(ActionPlan(steps: steps)) + case "Run": + // An unresolved ref yields null, which Action drops. + guard case .runtimeRef(let statementId, let refType)? = args.first else { return .null } + return .actionStep(.run(statementId: statementId, refType: refType)) + case "ToAssistant": + return .actionStep( + .continueConversation( + message: args.isEmpty ? "" : stringArg(0), context: args.count > 1 ? stringArg(1) : nil)) + case "OpenUrl": + return .actionStep(.openUrl(url: args.isEmpty ? "" : stringArg(0))) + case "Set": + // The value expression is kept as AST and evaluated when the action fires. + guard args.count >= 2, case .stateRef(let target) = args[0] else { return .null } + return .actionStep(.set(target: target, valueAST: args[1])) + case "Reset": + let targets = args.compactMap { arg -> String? in + if case .stateRef(let name) = arg { return name } + return nil + } + return targets.isEmpty ? .null : .actionStep(.reset(targets: targets)) + default: + return .null + } +} + +/// Replaces `Ref(varName)` with the loop item's literal value, so deferred +/// expressions (action steps) keep the item after the loop has finished. +func substituteRef(_ node: ASTNode, _ varName: String, _ value: OpenUIValue) -> ASTNode { + switch node { + case .ref(let name): + return name == varName ? toLiteralAST(value) : node + case .member(let obj, let field): + let substituted = substituteRef(obj, varName, value) + // `t.id` on a now-literal object resolves immediately. + if case .obj(let entries) = substituted, let entry = entries.first(where: { $0.key == field }) { + return entry.value + } + return .member(obj: substituted, field: field) + case .index(let obj, let index): + return .index( + obj: substituteRef(obj, varName, value), index: substituteRef(index, varName, value)) + case .binOp(let op, let left, let right): + return .binOp( + op: op, left: substituteRef(left, varName, value), right: substituteRef(right, varName, value) + ) + case .unaryOp(let op, let operand): + return .unaryOp(op: op, operand: substituteRef(operand, varName, value)) + case .ternary(let cond, let then, let otherwise): + return .ternary( + cond: substituteRef(cond, varName, value), then: substituteRef(then, varName, value), + else: substituteRef(otherwise, varName, value)) + case .arr(let elements): + return .arr(elements.map { substituteRef($0, varName, value) }) + case .obj(let entries): + return .obj(entries.map { ASTEntry($0.key, substituteRef($0.value, varName, value)) }) + case .comp(let name, let args, let mappedProps): + return .comp( + name: name, args: args.map { substituteRef($0, varName, value) }, + mappedProps: mappedProps?.map { ASTEntry($0.key, substituteRef($0.value, varName, value)) }) + case .assign(let target, let assigned): + return .assign(target: target, value: substituteRef(assigned, varName, value)) + default: + return node + } +} + +/// `@Each(array, varName, template)`: evaluates the template once per item. +private func evaluateLazyBuiltin( + _ name: String, _ args: [ASTNode], _ context: EvaluationContext, _ schema: SchemaContext? +) -> OpenUIValue { + guard name == "Each" else { return .null } + guard args.count >= 3, case .array(let items) = evaluate(args[0], context) else { + return .array([]) + } + let varName: String + switch args[1] { + case .ref(let n): varName = n + case .str(let v): varName = v + default: return .array([]) + } + let template = args[2] + return .array( + items.map { item in + let substituted = substituteRef(template, varName, item) + var childContext = context + childContext.resolveRef = { refName in + refName == varName ? item : context.resolveRef(refName) + } + let result = evaluate(substituted, childContext, schema) + if let schema, case .element(let element) = result { + return .element(evaluateElementInline(element, childContext, schema)) + } + return result + }) +} diff --git a/packages/swift-lang/Sources/OpenUILang/FormRules.swift b/packages/swift-lang/Sources/OpenUILang/FormRules.swift new file mode 100644 index 0000000000..d31610b4de --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/FormRules.swift @@ -0,0 +1,203 @@ +import Foundation + +/// A validation rule such as `required`, `min:8` or `pattern:^[a-z]`. +public struct ParsedRule: Sendable, Equatable { + public var type: String + public var arg: OpenUIValue? + + public init(type: String, arg: OpenUIValue? = nil) { + self.type = type + self.arg = arg + } +} + +private let numericRules: Set = ["min", "max", "minLength", "maxLength"] + +/// `"min:8"` → `{ type: "min", arg: 8 }`. +public func parseRule(_ rule: String) -> ParsedRule { + guard let colon = rule.firstIndex(of: ":") else { return ParsedRule(type: rule) } + let type = String(rule[.. [ParsedRule] { + (rules.arrayValue ?? []).compactMap(\.stringValue).map(parseRule) +} + +/// Parses a structured rules object: `{ required: true, minLength: 5 }`. +/// `false` and `null` entries are skipped. +public func parseStructuredRules(_ rules: OpenUIValue) -> [ParsedRule] { + guard case .object(let object) = rules else { return [] } + return object.entries.compactMap { key, value in + switch value { + case .bool(false), .null, .undefined: return nil + case .bool(true): return ParsedRule(type: key) + default: return ParsedRule(type: key, arg: value) + } + } +} + +public typealias ValidatorFn = @Sendable (OpenUIValue, OpenUIValue?) -> String? + +private func isEmpty(_ value: OpenUIValue) -> Bool { + switch value { + case .undefined, .null, .string(""): return true + case .array(let items): return items.isEmpty + case .object(let object): + // Form state stores { value, componentType }; check the actual value. + if let inner = object["value"] { return isEmpty(inner) } + // An empty object, e.g. a checkbox group with nothing selected. + return object.isEmpty + default: return false + } +} + +/// JavaScript `parseFloat`: the longest prefix that is a decimal literal, or NaN. +func jsParseFloat(_ string: String) -> Double { + let units = Array(jsTrim(string).utf8) + var i = 0 + func isDigit(_ index: Int) -> Bool { + index < units.count && units[index] >= UInt8(ascii: "0") && units[index] <= UInt8(ascii: "9") + } + var sign = "" + if i < units.count, units[i] == UInt8(ascii: "+") || units[i] == UInt8(ascii: "-") { + sign = units[i] == UInt8(ascii: "-") ? "-" : "" + i += 1 + } + if Array(units[i...]).starts(with: Array("Infinity".utf8)) { + return sign == "-" ? -.infinity : .infinity + } + var integer = "" + while isDigit(i) { + integer.append(Character(UnicodeScalar(units[i]))) + i += 1 + } + var fraction = "" + if i < units.count, units[i] == UInt8(ascii: ".") { + var j = i + 1 + while isDigit(j) { + fraction.append(Character(UnicodeScalar(units[j]))) + j += 1 + } + if !integer.isEmpty || !fraction.isEmpty { i = j } + } + guard !integer.isEmpty || !fraction.isEmpty else { return .nan } + var exponent = "" + if i < units.count, units[i] == UInt8(ascii: "e") || units[i] == UInt8(ascii: "E") { + var j = i + 1 + var expSign = "" + if j < units.count, units[j] == UInt8(ascii: "+") || units[j] == UInt8(ascii: "-") { + expSign = units[j] == UInt8(ascii: "-") ? "-" : "" + j += 1 + } + var digits = "" + while isDigit(j) { + digits.append(Character(UnicodeScalar(units[j]))) + j += 1 + } + if !digits.isEmpty { exponent = "e" + expSign + digits } + } + let literal = + sign + (integer.isEmpty ? "0" : integer) + (fraction.isEmpty ? "" : "." + fraction) + exponent + return Double(literal) ?? .nan +} + +private func numberArg(_ arg: OpenUIValue?) -> Double { + switch arg { + case .number(let number)?: return number + case .string(let string)?: return jsStringToNumber(string) + default: return .nan + } +} + +/// The built-in validators, keyed by rule type. Messages match lang-core. +public let builtInValidators: [String: ValidatorFn] = [ + "required": { value, _ in + if isEmpty(value) { return "This field is required" } + if case .object(let object) = value { + let values = object.values + let allBooleans = values.allSatisfy { $0.boolValue != nil } + if !values.isEmpty, allBooleans, !values.contains(.bool(true)) { + return "At least one option is required" + } + } + return nil + }, + "email": { value, _ in + if isEmpty(value) { return nil } + guard case .string(let string) = value else { return "Please enter a valid email" } + return string.range(of: #"^[^\s@]+@[^\s@]+\.[^\s@]+$"#, options: .regularExpression) != nil + ? nil : "Please enter a valid email" + }, + "url": { value, _ in + if isEmpty(value) { return nil } + guard case .string(let string) = value else { return "Please enter a valid URL" } + // `new URL(value)` requires an absolute URL with a scheme. + let hasScheme = + string.range(of: #"^[A-Za-z][A-Za-z0-9+.\-]*:"#, options: .regularExpression) != nil + return hasScheme && URL(string: string) != nil ? nil : "Please enter a valid URL" + }, + "numeric": { value, _ in + if isEmpty(value) { return nil } + if case .number(let number) = value, !number.isNaN { return nil } + if case .string(let string) = value, !jsParseFloat(string).isNaN, !jsTrim(string).isEmpty { + return nil + } + return "Must be a number" + }, + "min": { value, arg in + if isEmpty(value) { return nil } + let number = value.numberValue ?? jsParseFloat(value.jsString) + if number.isNaN { return nil } + let min = numberArg(arg) + return number >= min ? nil : "Must be at least \(jsNumberToString(min))" + }, + "max": { value, arg in + if isEmpty(value) { return nil } + let number = value.numberValue ?? jsParseFloat(value.jsString) + if number.isNaN { return nil } + let max = numberArg(arg) + return number <= max ? nil : "Must be no more than \(jsNumberToString(max))" + }, + "minLength": { value, arg in + if isEmpty(value) { return nil } + guard case .string(let string) = value else { return nil } + let min = numberArg(arg) + return Double(string.utf16.count) >= min + ? nil : "Must be at least \(jsNumberToString(min)) characters" + }, + "maxLength": { value, arg in + if isEmpty(value) { return nil } + guard case .string(let string) = value else { return nil } + let max = numberArg(arg) + return Double(string.utf16.count) <= max + ? nil : "Must be no more than \(jsNumberToString(max)) characters" + }, + "pattern": { value, arg in + if isEmpty(value) { return nil } + guard case .string(let string) = value, case .string(let pattern)? = arg, + let regex = try? NSRegularExpression(pattern: pattern) + else { return nil } + let range = NSRange(string.startIndex..., in: string) + return regex.firstMatch(in: string, range: range) != nil ? nil : "Invalid format" + }, +] + +/// Runs rules in order and returns the first error. Custom validators take +/// precedence over built-in ones; unknown rule types are skipped. +public func validate( + _ value: OpenUIValue, _ rules: [ParsedRule], customValidators: [String: ValidatorFn] = [:] +) -> String? { + for rule in rules { + guard let validator = customValidators[rule.type] ?? builtInValidators[rule.type] else { + continue + } + if let error = validator(value, rule.arg) { return error } + } + return nil +} diff --git a/packages/swift-lang/Sources/OpenUILang/QueryManager.swift b/packages/swift-lang/Sources/OpenUILang/QueryManager.swift new file mode 100644 index 0000000000..a49f6fd6e7 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/QueryManager.swift @@ -0,0 +1,475 @@ +/// Calls the tools behind `Query(...)` and `Mutation(...)` statements: MCP, +/// REST, GraphQL or anything else. +public protocol ToolProvider: Sendable { + func callTool(_ name: String, arguments: OpenUIObject) async throws -> OpenUIValue +} + +/// Thrown when a tool name has no handler. +public struct ToolNotFoundError: Error, CustomStringConvertible { + public var toolName: String + public var availableTools: [String] + + public init(toolName: String, availableTools: [String] = []) { + self.toolName = toolName + self.availableTools = availableTools + } + + public var description: String { + let available = availableTools.isEmpty ? "(none)" : availableTools.joined(separator: ", ") + return "[openui] No handler for tool \"\(toolName)\". Available: \(available)" + } +} + +/// A tool call that returned an MCP error result. +public struct McpToolError: Error, CustomStringConvertible { + public var toolErrorText: String + + public init(toolErrorText: String) { + self.toolErrorText = toolErrorText + } + + public var description: String { + "MCP tool error: \(toolErrorText.isEmpty ? "Unknown error" : toolErrorText)" + } +} + +/// Unwraps an MCP `callTool` result (`{ content, structuredContent, isError }`): +/// throws `McpToolError` for error results, prefers `structuredContent`, then +/// text content parsed as JSON (or returned as text). +public func extractToolResult(_ result: OpenUIValue) throws -> OpenUIValue { + let textParts = (result["content"].arrayValue ?? []) + .filter { $0["type"].stringValue == "text" } + .map { $0["text"].stringValue ?? "" } + if result["isError"].isTruthy { + let errorText = textParts.joined(separator: "\n") + throw McpToolError(toolErrorText: errorText.isEmpty ? "Unknown error" : errorText) + } + if !result["structuredContent"].isNullish { return result["structuredContent"] } + if !textParts.isEmpty { + let text = textParts.joined() + return (try? JSON.parse(text)) ?? .string(text) + } + return .null +} + +/// A tool provider backed by a map of async handlers. +public struct FunctionToolProvider: ToolProvider { + public typealias Handler = @Sendable (OpenUIObject) async throws -> OpenUIValue + + private let handlers: [String: Handler] + + public init(_ handlers: [String: Handler]) { + self.handlers = handlers + } + + public func callTool(_ name: String, arguments: OpenUIObject) async throws -> OpenUIValue { + guard let handler = handlers[name] else { + throw ToolNotFoundError(toolName: name, availableTools: handlers.keys.sorted()) + } + return try await handler(arguments) + } +} + +/// A Query statement evaluated against the current state. +public struct QueryNode: Sendable { + public var statementId: String + public var toolName: String + public var args: OpenUIValue + public var defaults: OpenUIValue + public var refreshInterval: Double? + /// Values of the `$state` the query depends on; part of the cache key. + public var deps: OpenUIObject? + public var complete: Bool +} + +public struct MutationNode: Sendable { + public var statementId: String + public var toolName: String +} + +/// Query results and status, published to observers when anything changes. +public struct QuerySnapshot: Sendable, Equatable { + /// Result per Query statement (data, previous data, or defaults) and per + /// Mutation statement (`{ status, data?, error? }`). + public var results: OpenUIObject = OpenUIObject() + public var loading: [String] = [] + public var refetching: [String] = [] + public var errors: [OpenUIError] = [] +} + +private func stableStringify(_ value: OpenUIValue) -> String { + func normalize(_ value: OpenUIValue) -> OpenUIValue { + switch value { + case .undefined: return "__undefined__" + case .number(let number) where number.isNaN: return "__NaN__" + case .number(let number) where number == .infinity: return "__Inf__" + case .number(let number) where number == -.infinity: return "__-Inf__" + case .array(let items): return .array(items.map(normalize)) + case .object(let object): + return .object(OpenUIObject(object.keys.sorted().map { ($0, normalize(object[$0]!)) })) + default: return value + } + } + return JSON.stringify(normalize(value.jsonRepresentation)) +} + +private func cacheKey(_ toolName: String, _ args: OpenUIValue, _ deps: OpenUIObject?) -> String { + let depsKey = deps.map { "::" + stableStringify(.object($0)) } ?? "" + return toolName + "::" + stableStringify(args) + depsKey +} + +/// Fetches, caches and refreshes Query results and runs Mutations. Ports +/// lang-core's `createQueryManager`. +@MainActor +public final class QueryManager { + private struct QueryEntry { + var toolName: String + var args: OpenUIValue + var defaults: OpenUIValue + var cacheKey: String + var prevCacheKey: String? + var loading = false + var everFetched = false + var refreshInterval: Double = 0 + var timer: Task? + var needsRefetch = false + var error: OpenUIError? + } + + private struct MutationEntry { + var toolName: String + var result: OpenUIValue + var error: OpenUIError? + } + + private struct CacheEntry { + var data: OpenUIValue = .undefined + var inFlight = false + } + + private let toolProvider: (any ToolProvider)? + private var queryOrder: [String] = [] + private var queries: [String: QueryEntry] = [:] + private var mutationOrder: [String] = [] + private var mutations: [String: MutationEntry] = [:] + private var cache: [String: CacheEntry] = [:] + private var listeners: [Int: () -> Void] = [:] + private var nextListenerId = 0 + private var disposed = false + private var generation = 0 + + public private(set) var snapshot = QuerySnapshot() + + public init(toolProvider: (any ToolProvider)?) { + self.toolProvider = toolProvider + } + + // MARK: Snapshot + + @discardableResult + private func rebuildSnapshot() -> Bool { + var out = QuerySnapshot() + for id in queryOrder { + guard let query = queries[id] else { continue } + out.results[id] = resultValue(query) + if query.loading { + out.loading.append(id) + if query.everFetched { out.refetching.append(id) } + } + if let error = query.error { out.errors.append(error) } + } + for id in mutationOrder { + guard let mutation = mutations[id] else { continue } + out.results[id] = mutation.result + if let error = mutation.error { out.errors.append(error) } + } + guard out != snapshot else { return false } + snapshot = out + return true + } + + private func resultValue(_ query: QueryEntry) -> OpenUIValue { + if let data = cache[query.cacheKey]?.data, data != .undefined { return data } + if let previous = query.prevCacheKey, let data = cache[previous]?.data, data != .undefined { + return data + } + return query.defaults + } + + private func notify() { + for listener in listeners.sorted(by: { $0.key < $1.key }).map(\.value) { listener() } + } + + @discardableResult + public func subscribe(_ listener: @escaping () -> Void) -> () -> Void { + let id = nextListenerId + nextListenerId += 1 + listeners[id] = listener + return { [weak self] in self?.listeners[id] = nil } + } + + // MARK: Queries + + /// Starts a fetch. Like the JavaScript async function, everything before the + /// tool call runs synchronously, so the query is marked loading right away. + private func startFetch(_ fetchKey: String, _ statementId: String) { + guard let toolProvider, let query = queries[statementId] else { return } + let toolName = query.toolName + let args = query.args.objectValue ?? OpenUIObject() + cache[fetchKey, default: CacheEntry()].inFlight = true + queries[statementId]?.loading = true + rebuildSnapshot() + notify() + Task { + let outcome: Result + do { + outcome = .success(try await toolProvider.callTool(toolName, arguments: args)) + } catch { + outcome = .failure(error) + } + finishFetch(fetchKey, statementId, toolName, outcome) + } + } + + private func finishFetch( + _ fetchKey: String, _ statementId: String, _ toolName: String, + _ outcome: Result + ) { + switch outcome { + case .success(let data): + if disposed { return } + guard queries[statementId]?.cacheKey == fetchKey else { + cache[fetchKey]?.inFlight = false + return + } + cache[fetchKey]?.data = data.isNullish ? .null : data + queries[statementId]?.everFetched = true + queries[statementId]?.error = nil + if let previous = queries[statementId]?.prevCacheKey, previous != fetchKey { + queries[statementId]?.prevCacheKey = nil + cleanupCacheEntry(previous) + } + case .failure(let error): + if queries[statementId]?.cacheKey == fetchKey { + queries[statementId]?.error = queryError( + error, toolName: toolName, statementId: statementId) + } + } + + cache[fetchKey]?.inFlight = false + if queries[statementId]?.cacheKey == fetchKey { + queries[statementId]?.loading = false + if rebuildSnapshot() { notify() } + if queries[statementId]?.needsRefetch == true { + queries[statementId]?.needsRefetch = false + startFetch(queries[statementId]!.cacheKey, statementId) + } + } else if rebuildSnapshot() { + notify() + } + } + + private func queryError(_ error: Error, toolName: String, statementId: String) -> OpenUIError { + if let error = error as? ToolNotFoundError { + return OpenUIError( + source: .query, code: "tool-not-found", message: "Query tool \"\(toolName)\" not found", + statementId: statementId, component: "Query", toolName: toolName, + hint: error.availableTools.isEmpty + ? nil : "Available tools: \(error.availableTools.joined(separator: ", "))") + } + if let error = error as? McpToolError { + return OpenUIError( + source: .query, code: "mcp-error", + message: "Query \"\(toolName)\" returned an error: \(error.toolErrorText)", + statementId: statementId, component: "Query", toolName: toolName) + } + return OpenUIError( + source: .query, code: "tool-error", message: "Query \"\(toolName)\" failed: \(error)", + statementId: statementId, component: "Query", toolName: toolName) + } + + private func cleanupCacheEntry(_ key: String) { + for query in queries.values where query.cacheKey == key || query.prevCacheKey == key { return } + cache[key] = nil + } + + /// Syncs the active Query statements: drops removed ones, fetches new or + /// changed ones, and (re)schedules refresh intervals. + public func evaluateQueries(_ nodes: [QueryNode]) { + if disposed { return } + let activeIds = Set(nodes.map(\.statementId)) + for id in queryOrder where !activeIds.contains(id) { + guard let query = queries.removeValue(forKey: id) else { continue } + query.timer?.cancel() + cleanupCacheEntry(query.cacheKey) + if let previous = query.prevCacheKey { cleanupCacheEntry(previous) } + } + queryOrder.removeAll { !activeIds.contains($0) } + + for node in nodes where node.complete { + let key = cacheKey(node.toolName, node.args, node.deps) + if var existing = queries[node.statementId] { + if existing.cacheKey != key { existing.prevCacheKey = existing.cacheKey } + existing.toolName = node.toolName + existing.args = node.args + existing.defaults = node.defaults + existing.cacheKey = key + queries[node.statementId] = existing + } else { + queries[node.statementId] = QueryEntry( + toolName: node.toolName, args: node.args, defaults: node.defaults, cacheKey: key) + queryOrder.append(node.statementId) + } + + let entry = cache[key] + let hasSettledData = entry.map { $0.data != .undefined && !$0.inFlight } ?? false + if toolProvider != nil, !hasSettledData, entry?.inFlight != true { + startFetch(key, node.statementId) + } + + let interval = node.refreshInterval ?? 0 + if interval != queries[node.statementId]!.refreshInterval { + queries[node.statementId]!.timer?.cancel() + queries[node.statementId]!.timer = nil + if interval > 0 { + let statementId = node.statementId + queries[node.statementId]!.timer = Task { [weak self] in + while !Task.isCancelled { + try? await Task.sleep(nanoseconds: UInt64(interval * 1_000_000_000)) + guard let self, !Task.isCancelled, !self.disposed, self.toolProvider != nil, + let current = self.queries[statementId] + else { return } + if self.cache[current.cacheKey]?.inFlight != true { + self.startFetch(current.cacheKey, statementId) + } + } + } + } + queries[node.statementId]!.refreshInterval = interval + } + } + if rebuildSnapshot() { notify() } + } + + /// The current value for a Query: fetched data, the previous result while a + /// new key loads, or the declared defaults. `null` for unknown statements. + public func result(_ statementId: String) -> OpenUIValue { + guard let query = queries[statementId] else { return .null } + return resultValue(query) + } + + public func isLoading(_ statementId: String) -> Bool { queries[statementId]?.loading ?? false } + + public var isAnyLoading: Bool { queries.values.contains { $0.loading } } + + /// Refetches the given queries (all when nil or empty). Queries already in + /// flight refetch once they settle. + public func invalidate(_ statementIds: [String]? = nil) { + if disposed || toolProvider == nil { return } + let targets = + (statementIds?.isEmpty == false) ? statementIds!.filter { queries[$0] != nil } : queryOrder + for id in targets { + guard let query = queries[id] else { continue } + if cache[query.cacheKey]?.inFlight == true { + queries[id]?.needsRefetch = true + } else { + startFetch(query.cacheKey, id) + } + } + } + + // MARK: Mutations + + public func registerMutations(_ nodes: [MutationNode]) { + let activeIds = Set(nodes.map(\.statementId)) + for id in mutationOrder where !activeIds.contains(id) { mutations[id] = nil } + mutationOrder.removeAll { !activeIds.contains($0) } + for node in nodes { + if let existing = mutations[node.statementId] { + if existing.toolName != node.toolName { + mutations[node.statementId] = MutationEntry( + toolName: node.toolName, result: ["status": "idle", "data": .null, "error": .null]) + } + } else { + mutations[node.statementId] = MutationEntry( + toolName: node.toolName, result: ["status": "idle"]) + mutationOrder.append(node.statementId) + } + } + if rebuildSnapshot() { notify() } + } + + /// Runs a mutation. Returns false when it fails, is already running, or + /// there is no tool provider; a failure halts the action's remaining steps. + public func fireMutation( + _ statementId: String, args: OpenUIObject, refreshQueryIds: [String]? = nil + ) async -> Bool { + if disposed || toolProvider == nil { return false } + guard let mutation = mutations[statementId], mutation.result["status"].stringValue != "loading" + else { return false } + let currentGeneration = generation + mutations[statementId]?.result = ["status": "loading"] + rebuildSnapshot() + notify() + + var success = false + do { + let data = try await toolProvider!.callTool(mutation.toolName, arguments: args) + if disposed || currentGeneration != generation { return false } + mutations[statementId]?.result = ["status": "success", "data": data] + mutations[statementId]?.error = nil + success = true + } catch { + if disposed || currentGeneration != generation { return false } + mutations[statementId]?.result = ["status": "error", "error": .string("\(error)")] + mutations[statementId]?.error = mutationError( + error, toolName: mutation.toolName, statementId: statementId) + } + rebuildSnapshot() + notify() + if success, let refreshQueryIds, !refreshQueryIds.isEmpty { invalidate(refreshQueryIds) } + return success + } + + private func mutationError(_ error: Error, toolName: String, statementId: String) -> OpenUIError { + if let error = error as? ToolNotFoundError { + return OpenUIError( + source: .mutation, code: "tool-not-found", + message: "Mutation tool \"\(toolName)\" not found", statementId: statementId, + component: "Mutation", toolName: toolName, + hint: error.availableTools.isEmpty + ? nil : "Available tools: \(error.availableTools.joined(separator: ", "))") + } + if let error = error as? McpToolError { + return OpenUIError( + source: .mutation, code: "mcp-error", + message: "Mutation \"\(toolName)\" returned an error: \(error.toolErrorText)", + statementId: statementId, component: "Mutation", toolName: toolName) + } + return OpenUIError( + source: .mutation, code: "tool-error", message: "Mutation \"\(toolName)\" failed: \(error)", + statementId: statementId, component: "Mutation", toolName: toolName) + } + + /// `{ status, data?, error? }` for a Mutation statement, or nil. + public func mutationResult(_ statementId: String) -> OpenUIValue? { + mutations[statementId]?.result + } + + public func activate() { disposed = false } + + public func dispose() { + disposed = true + generation += 1 + listeners.removeAll() + for id in queryOrder { + queries[id]?.timer?.cancel() + queries[id]?.timer = nil + queries[id]?.refreshInterval = 0 + queries[id]?.loading = false + queries[id]?.needsRefetch = false + } + mutations.removeAll() + mutationOrder.removeAll() + } +} diff --git a/packages/swift-lang/Sources/OpenUILang/Runtime.swift b/packages/swift-lang/Sources/OpenUILang/Runtime.swift new file mode 100644 index 0000000000..47c7e8576b --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Runtime.swift @@ -0,0 +1,251 @@ +/// What the parser and evaluator need to know about a component library. +public protocol ComponentLibrary { + /// Positional parameters per component, compiled from the library schema. + var paramMap: ParamMap { get } + /// The root component, used to pick the entry statement. + var rootName: String? { get } + /// Whether a prop binds two-way to `$state` (lang-core's `reactive()`). + func isReactiveProp(_ component: String, _ prop: String) -> Bool +} + +/// The framework-independent runtime behind a renderer: streaming parse, +/// state store, prop evaluation, form fields and action execution. Ports the +/// logic of react-lang's `useOpenUIState`; UI layers observe it and render. +@MainActor +public final class OpenUIRuntime { + public let library: any ComponentLibrary + public let store = Store() + public let queries: QueryManager + + /// Called for actions the host handles (continue the conversation, open a URL, custom). + public var onAction: ((ActionEvent) -> Void)? + /// Called when state changes after initialization. + public var onStateUpdate: ((OpenUIObject) -> Void)? + + public private(set) var parseResult: ParseResult? + public private(set) var isStreaming = false + + private let streamParser: StreamParser + private let initialState: OpenUIObject? + private var storeInitKey: String? + private var initializingStore = false + private var unsubscribe: (() -> Void)? + + public init( + library: some ComponentLibrary, initialState: OpenUIObject? = nil, + toolProvider: (any ToolProvider)? = nil + ) { + self.library = library + self.initialState = initialState + self.streamParser = StreamParser(library.paramMap, rootName: library.rootName) + self.queries = QueryManager(toolProvider: toolProvider) + unsubscribe = store.subscribe { [weak self] in + guard let self, !self.initializingStore else { return } + self.onStateUpdate?(self.store.snapshot) + } + } + + /// Stops query refreshes and drops listeners. + public func dispose() { + unsubscribe?() + unsubscribe = nil + queries.dispose() + } + + // MARK: Parsing + + /// Feeds the latest full response text. Appended text parses incrementally. + public func update(response: String?, isStreaming: Bool) { + self.isStreaming = isStreaming + guard let response, !response.isEmpty else { + parseResult = nil + return + } + parseResult = streamParser.set(response) + initializeStoreIfNeeded() + if !isStreaming { syncQueries() } + } + + /// Seeds the store from `$state` declarations and `initialState` whenever + /// either changes. Values the user already changed are kept. + private func initializeStoreIfNeeded() { + let declarations = parseResult?.stateDeclarations ?? OpenUIObject() + let key = + JSON.stringify(.object(declarations)) + "::" + + (initialState.map { JSON.stringify(.object($0)) } ?? "") + guard key != storeInitKey else { return } + storeInitKey = key + + initializingStore = true + defer { initializingStore = false } + var bindingDefaults = OpenUIObject() + for (key, value) in initialState ?? OpenUIObject() { + if key.hasPrefix("$") { + bindingDefaults[key] = value + } else { + store.set(key, value) + } + } + store.initialize(defaults: declarations, persisted: bindingDefaults) + } + + // MARK: Evaluation + + /// Reads state for expressions (form fields store `{ value, componentType }`) + /// and Query/Mutation results as of now. + public var evaluationContext: EvaluationContext { + let results = queries.snapshot.results + return EvaluationContext( + getState: { [store] name in unwrapFieldValue(store.get(name)) }, + resolveRef: { name in results[name] ?? .null }) + } + + public var schemaContext: SchemaContext { + SchemaContext(isReactiveProp: library.isReactiveProp) + } + + /// The parsed root with every prop evaluated against the current state. + public func evaluatedRoot() -> ElementNode? { + guard let root = parseResult?.root else { return nil } + return evaluateElementProps(root, evaluationContext, schemaContext) + } + + // MARK: Fields + + public func fieldValue(form: String?, name: String) -> OpenUIValue { + guard let form else { return unwrapFieldValue(store.get(name)) } + guard case .object(let formData) = store.get(form) else { return .undefined } + return unwrapFieldValue(formData[name] ?? .undefined) + } + + public func setFieldValue( + form: String?, componentType: String?, name: String, value: OpenUIValue, + notifyHost: Bool = true + ) { + var wrapped: OpenUIObject = ["value": value] + wrapped["componentType"] = componentType.map { .string($0) } ?? .undefined + if let form { + var formData = store.get(form).objectValue ?? OpenUIObject() + formData[name] = .object(wrapped) + store.set(form, .object(formData)) + } else { + store.set(name, .object(wrapped)) + } + if notifyHost { onStateUpdate?(store.snapshot) } + } + + /// The field a component reads and writes for `name`, honouring `$state` bindings. + public func stateField(name: String, binding: OpenUIValue, form: String?) -> StateField { + resolveStateField( + name: name, bindingValue: binding, store: store, evaluationContext: evaluationContext, + getField: { [weak self] field in self?.fieldValue(form: form, name: field) ?? .undefined }, + setField: { [weak self] field, value in + self?.setFieldValue(form: form, componentType: nil, name: field, value: value) + }) + } + + /// The state sent along with an action: the named form, or everything. + public func formPayload(_ form: String?) -> OpenUIObject { + if let form, case .object = store.get(form) { return [form: store.get(form)] } + return store.snapshot + } + + // MARK: Actions + + /// Runs a component's action. `action` is an evaluated `Action([...])` plan, + /// a legacy `{ type, params }` object, or nil (continue the conversation + /// with the label as the message). + public func triggerAction(_ userMessage: String, form: String? = nil, action: OpenUIValue? = nil) + async + { + let payload = formPayload(form) + + if case .object(let legacy)? = action { + var params = legacy["params"]?.objectValue ?? OpenUIObject() + if let url = legacy["url"], !url.isNullish { params["url"] = url } + if let context = legacy["context"], !context.isNullish { params["context"] = context } + let type = legacy["type"]?.stringValue.flatMap { $0.isEmpty ? nil : $0 } + onAction?( + ActionEvent( + type: type ?? BuiltinActionType.continueConversation, params: params, + humanFriendlyMessage: userMessage, formState: payload, formName: form)) + return + } + + guard case .actionPlan(let plan)? = action else { + onAction?( + ActionEvent( + type: BuiltinActionType.continueConversation, humanFriendlyMessage: userMessage, + formState: payload, formName: form)) + return + } + + for step in plan.steps { + switch step { + case .run(let statementId, let refType): + if refType == .mutation { + let argsAST = parseResult?.mutationStatements.first { $0.statementId == statementId }? + .argsAST + let args = argsAST.map { evaluate($0, evaluationContext) }?.objectValue ?? OpenUIObject() + // A failed mutation halts the remaining steps. + guard await queries.fireMutation(statementId, args: args) else { return } + } else { + queries.invalidate([statementId]) + } + case .continueConversation(let message, let context): + onAction?( + ActionEvent( + type: BuiltinActionType.continueConversation, + params: context.map { ["context": .string($0)] } ?? OpenUIObject(), + humanFriendlyMessage: message, formState: payload, formName: form)) + case .openUrl(let url): + onAction?( + ActionEvent( + type: BuiltinActionType.openUrl, params: ["url": .string(url)], + humanFriendlyMessage: "", formState: payload, formName: form)) + case .set(let target, let valueAST): + store.set(target, evaluate(valueAST, evaluationContext)) + case .reset(let targets): + let declarations = parseResult?.stateDeclarations ?? OpenUIObject() + for target in targets { + let declared = declarations[target] ?? .null + store.set(target, declared.isNullish ? .null : declared) + } + } + } + } + + // MARK: Queries + + /// Evaluates Query/Mutation statements against the current state and hands + /// them to the query manager. Runs once the stream has finished. + public func syncQueries() { + guard let result = parseResult, !isStreaming else { return } + let context = evaluationContext + let snapshot = store.snapshot + queries.evaluateQueries( + result.queryStatements.map { query in + var deps = OpenUIObject() + for dep in query.deps ?? [] { deps[dep] = snapshot[dep] ?? .undefined } + return QueryNode( + statementId: query.statementId, + toolName: query.toolAST.map { evaluate($0, context) }?.stringValue ?? "", + args: query.argsAST.map { evaluate($0, context) } ?? .null, + defaults: query.defaultsAST.map { evaluate($0, context) } ?? .null, + refreshInterval: query.refreshAST.map { evaluate($0, context) }?.numberValue, + deps: deps.isEmpty ? nil : deps, complete: query.complete) + }) + queries.registerMutations( + result.mutationStatements.map { mutation in + MutationNode( + statementId: mutation.statementId, + toolName: mutation.toolAST.map { evaluate($0, context) }?.stringValue ?? "") + }) + } +} + +/// Form fields store `{ value, componentType }`; expressions see the raw value. +func unwrapFieldValue(_ value: OpenUIValue) -> OpenUIValue { + if case .object(let object) = value, let inner = object["value"] { return inner } + return value +} diff --git a/packages/swift-lang/Sources/OpenUILang/Store.swift b/packages/swift-lang/Sources/OpenUILang/Store.swift new file mode 100644 index 0000000000..b7d168e2b3 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Store.swift @@ -0,0 +1,94 @@ +import Foundation + +/// The reactive state store: `$bindings` as top-level keys, form fields nested +/// under their form name. +public final class Store { + private var state = OpenUIObject() + private var listeners: [UUID: () -> Void] = [:] + private var listenerOrder: [UUID] = [] + + public init() {} + + public func get(_ name: String) -> OpenUIValue { + state[name] ?? .undefined + } + + /// Sets a value and notifies listeners, unless the value is unchanged (plain + /// objects compare shallowly, as form data is replaced on every edit). + public func set(_ name: String, _ value: OpenUIValue) { + let existing = state[name] ?? .undefined + if existing.isSameValue(value) { return } + if case .object(let next) = value, case .object(let current) = existing, + next.keys.count == current.keys.count, + next.keys.allSatisfy({ (next[$0] ?? .undefined).isSameValue(current[$0] ?? .undefined) }) + { + return + } + state[name] = value + notify() + } + + /// Registers a listener; returns a function that removes it. + @discardableResult + public func subscribe(_ listener: @escaping () -> Void) -> () -> Void { + let id = UUID() + listeners[id] = listener + listenerOrder.append(id) + return { [weak self] in + self?.listeners[id] = nil + self?.listenerOrder.removeAll { $0 == id } + } + } + + public var snapshot: OpenUIObject { state } + + /// Applies persisted values, then defaults for keys that don't exist yet. + /// Values the user already changed are never overwritten or deleted: while + /// streaming, declarations can briefly disappear and deleting would lose input. + public func initialize(defaults: OpenUIObject, persisted: OpenUIObject) { + for (key, value) in persisted { state[key] = value } + for (key, value) in defaults where !state.contains(key) { state[key] = value } + notify() + } + + public func dispose() { + state = OpenUIObject() + listeners.removeAll() + listenerOrder.removeAll() + } + + private func notify() { + for id in listenerOrder { listeners[id]?() } + } +} + +/// A form field or `$binding` a component reads and writes. +public struct StateField { + public var name: String + public var value: OpenUIValue + public var setValue: (OpenUIValue) -> Void + /// True when the field is bound to a `$state` variable. + public var isReactive: Bool +} + +/// Resolves the field a component should read and write: a reactive binding +/// when the prop is bound to `$state`, otherwise the form field `name`. +public func resolveStateField( + name: String, bindingValue: OpenUIValue, store: Store?, evaluationContext: EvaluationContext?, + getField: @escaping (String) -> OpenUIValue, + setField: @escaping (String, OpenUIValue) -> Void +) -> StateField { + if case .reactiveAssign(let assign) = bindingValue, let store, let evaluationContext { + return StateField( + name: name, value: store.get(assign.target), + setValue: { newValue in + var context = evaluationContext + context.extraScope = ["$value": newValue] + store.set(assign.target, evaluate(assign.expr, context)) + }, isReactive: true) + } + let current = getField(name) + return StateField( + name: name, value: current.isNullish ? bindingValue : current, + setValue: { setField(name, $0) }, isReactive: false) +} diff --git a/packages/swift-lang/Sources/OpenUILang/Value.swift b/packages/swift-lang/Sources/OpenUILang/Value.swift index 7493d4cfe2..55c77e3300 100644 --- a/packages/swift-lang/Sources/OpenUILang/Value.swift +++ b/packages/swift-lang/Sources/OpenUILang/Value.swift @@ -140,3 +140,9 @@ private func arrayIndex(_ key: String) -> UInt32? { guard let value = UInt32(key), value != UInt32.max, String(value) == key else { return nil } return value } + +extension OpenUIObject: ExpressibleByDictionaryLiteral { + public init(dictionaryLiteral elements: (String, OpenUIValue)...) { + self.init(elements) + } +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/EvaluationConformanceTests.swift b/packages/swift-lang/Tests/OpenUILangTests/EvaluationConformanceTests.swift new file mode 100644 index 0000000000..031df391ca --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/EvaluationConformanceTests.swift @@ -0,0 +1,41 @@ +import Testing + +@testable import OpenUILang + +extension Fixtures { + static func schemaContext(_ schemaName: String) -> SchemaContext { + let reactive = schemas[schemaName]["reactive"].objectValue ?? OpenUIObject() + return SchemaContext { component, prop in + (reactive[component]?.arrayValue ?? []).contains(.string(prop)) + } + } +} + +/// Prop evaluation must match lang-core's `evaluateElementProps`. +@Suite struct EvaluationConformanceTests { + @Test(arguments: FixtureCase.all("evaluation")) + func evaluateTree(_ fixture: FixtureCase) { + let schema = fixture.value["schema"].stringValue! + let result = OpenUILang.parse( + fixture.value["input"].stringValue!, Fixtures.paramMap(schema), + rootName: Fixtures.rootName(schema)) + + let store = Store() + store.initialize(defaults: result.stateDeclarations, persisted: OpenUIObject()) + for (key, value) in fixture.value["state"].objectValue ?? OpenUIObject() { + store.set(key, value) + } + let queryResults = fixture.value["queryResults"].objectValue ?? OpenUIObject() + let context = EvaluationContext( + getState: { unwrapFieldValue(store.get($0)) }, + resolveRef: { queryResults[$0] ?? .null }) + + let root = result.root.map { + evaluateElementProps($0, context, Fixtures.schemaContext(schema)) + } + let diff = firstDifference( + normalized(root.map(\.jsonRepresentation) ?? .null), + normalized(fixture.value["expected"]["root"])) + #expect(diff == nil, "\(fixture.name): \(diff ?? "")") + } +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/evaluation.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/evaluation.json new file mode 100644 index 0000000000..ab8a234526 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/evaluation.json @@ -0,0 +1,3562 @@ +[ + { + "name": "chat-example-1", + "schema": "chat", + "input": "Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "CardHeader", + "props": { + "title": "Paris", + "subtitle": "The City of Light · France's Eternal Capital" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "header" + }, + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]." + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "intro" + }, + { + "type": "element", + "typeName": "ContextCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "ContextCardItem", + "props": { + "id": "art-museums", + "title": "Art & Museums", + "body": "143 museums including the Louvre & newly reopened Grand Palais.", + "bgColor": "gray", + "bgImageSrc": "https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "h1" + }, + { + "type": "element", + "typeName": "ContextCardItem", + "props": { + "id": "gastronomy", + "title": "Gastronomy", + "body": "9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.", + "bgColor": "gray" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "h2" + }, + { + "type": "element", + "typeName": "ContextCardItem", + "props": { + "id": "fashion-capital", + "title": "Fashion Capital", + "body": "Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.", + "bgColor": "gray", + "bgImageSrc": "https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "h3" + } + ], + "layout": "grid", + "responsive": true, + "action": { + "type": "continue_conversation", + "context": "Tell me more about this aspect of Paris" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "highlights" + }, + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "Paris by the Numbers", + "description": "Key visitor statistics" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "statsHeader" + }, + { + "type": "element", + "typeName": "OverviewCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "OverviewCardItem", + "props": { + "id": "annual-visitors", + "top": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "users", + "category": "people" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov1icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Annual Visitors", + "subtitle": "2024 arrivals", + "bold": false, + "layout": "vertical" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov1top" + }, + "bottom": { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "48.7M", + "subtext": "tourists", + "trend": { + "direction": "up", + "value": 2.5 + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov1metric" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov1" + }, + { + "type": "element", + "typeName": "OverviewCardItem", + "props": { + "id": "museums-monuments", + "top": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "landmark", + "category": "buildings" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov2icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Museums & Monuments", + "subtitle": "Cultural sites", + "bold": false, + "layout": "vertical" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov2top" + }, + "bottom": { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "2,370+", + "subtext": "across the city" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov2metric" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov2" + }, + { + "type": "element", + "typeName": "OverviewCardItem", + "props": { + "id": "tourism-revenue", + "top": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "circle-dollar-sign", + "category": "finance" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov3icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Tourism Revenue", + "subtitle": "2024 estimate", + "bold": false, + "layout": "vertical" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov3top" + }, + "bottom": { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "€23.4B", + "subtext": "generated" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov3metric" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ov3" + } + ], + "layout": "grid", + "responsive": true + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "statsCards" + }, + { + "type": "element", + "typeName": "SectionBlock", + "props": { + "sections": [ + { + "type": "element", + "typeName": "SectionItem", + "props": { + "value": "landmarks", + "trigger": "Iconic Landmarks", + "content": [ + { + "type": "element", + "typeName": "VisualCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Eiffel Tower", + "subtext": "Open daily 9am–midnight", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm1body" + }, + "id": "eiffel-tower", + "bgImageSrc": "https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "Must-See", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "star", + "category": "shapes" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm1tagIcon" + }, + "size": "sm", + "variant": "info" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm1tag" + }, + "bgImageAlt": "Aerial view of the Eiffel Tower" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm1" + }, + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "The Louvre", + "subtext": "World's largest art museum", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm2body" + }, + "id": "the-louvre", + "bgImageSrc": "https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "8.9M visits/yr", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "trending-up", + "category": "charts" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm2tagIcon" + }, + "size": "sm", + "variant": "success" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm2tag" + }, + "bgImageAlt": "Exterior of the Louvre museum" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm2" + }, + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Notre-Dame", + "subtext": "Fully restored cathedral", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm3body" + }, + "id": "notre-dame", + "bgImageSrc": "https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "Reopened 2024", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "hammer", + "category": "tools" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm3tagIcon" + }, + "size": "sm", + "variant": "warning" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm3tag" + }, + "bgImageAlt": "Notre-Dame cathedral facade" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm3" + }, + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Palace of Versailles", + "subtext": "Royal gardens & grand halls", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm4body" + }, + "id": "versailles", + "bgImageSrc": "https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "Day Trip", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "train-front", + "category": "travel" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm4tagIcon" + }, + "size": "sm", + "variant": "neutral" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm4tag" + }, + "bgImageAlt": "Latona Fountain at Versailles" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "lm4" + } + ], + "layout": "carousel", + "responsive": true, + "action": { + "type": "continue_conversation", + "context": "Tell me more about this Paris landmark" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "landmarksCarousel" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "secLandmarks" + }, + { + "type": "element", + "typeName": "SectionItem", + "props": { + "value": "food", + "trigger": "Food & Drink", + "content": [ + { + "type": "element", + "typeName": "ContextCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "ContextCardItem", + "props": { + "id": "bistros", + "title": "Bistros", + "body": "Classic French fare — try Les Arlots for confit beef cheeks.", + "bgColor": "gray", + "bgImageSrc": "https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "f1" + }, + { + "type": "element", + "typeName": "ContextCardItem", + "props": { + "id": "fine-dining", + "title": "Fine Dining", + "body": "Septime leads a new wave of creative Michelin-starred cuisine.", + "bgColor": "gray", + "bgImageSrc": "https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "f2" + }, + { + "type": "element", + "typeName": "ContextCardItem", + "props": { + "id": "bakeries", + "title": "Bakeries", + "body": "Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.", + "bgColor": "gray", + "bgImageSrc": "https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "f3" + } + ], + "layout": "grid", + "responsive": true, + "action": { + "type": "continue_conversation", + "context": "Tell me more about eating and drinking in Paris" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "foodCards" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "secFood" + }, + { + "type": "element", + "typeName": "SectionItem", + "props": { + "value": "when", + "trigger": "Best Time to Visit", + "content": [ + { + "type": "element", + "typeName": "Tabs", + "props": { + "items": [ + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "spring", + "trigger": "Spring", + "content": [ + { + "type": "element", + "typeName": "ListBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "ListItem", + "props": { + "title": "Cherry blossoms at Parc de Sceaux", + "subtitle": "March – May", + "image": null, + "actionLabel": null, + "action": { + "type": "continue_conversation", + "context": "Tell me about cherry blossom season in Paris" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "sp1" + }, + { + "type": "element", + "typeName": "ListItem", + "props": { + "title": "Picnics along the Seine & in city parks", + "subtitle": "Warm, lively atmosphere", + "image": null, + "actionLabel": null, + "action": { + "type": "continue_conversation", + "context": "Where are the best picnic spots in Paris?" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "sp2" + }, + { + "type": "element", + "typeName": "ListItem", + "props": { + "title": "Fewer crowds than summer", + "subtitle": "Ideal for sightseeing", + "image": null, + "actionLabel": null, + "action": { + "type": "continue_conversation", + "context": "How busy is Paris in spring?" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "sp3" + } + ], + "variant": "number" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "springList" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabSpring" + }, + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "summer", + "trigger": "Summer", + "content": [ + { + "type": "element", + "typeName": "ListBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "ListItem", + "props": { + "title": "Swim in the Seine — open July & August 2026", + "subtitle": "First time in 102 years", + "image": null, + "actionLabel": null, + "action": { + "type": "continue_conversation", + "context": "Tell me about swimming in the Seine" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "su1" + }, + { + "type": "element", + "typeName": "ListItem", + "props": { + "title": "Open-air cinema at Parc de la Villette", + "subtitle": "Free films under the stars", + "image": null, + "actionLabel": null, + "action": { + "type": "continue_conversation", + "context": "Tell me about the open-air cinema at Parc de la Villette" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "su2" + }, + { + "type": "element", + "typeName": "ListItem", + "props": { + "title": "Bastille Day celebrations on July 14", + "subtitle": "Fireworks at the Eiffel Tower", + "image": null, + "actionLabel": null, + "action": { + "type": "continue_conversation", + "context": "What happens in Paris on Bastille Day?" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "su3" + } + ], + "variant": "number" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "summerList" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabSummer" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "whenTabs" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "secWhen" + } + ], + "isFoldable": false + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "sectionsBlock" + }, + { + "type": "element", + "typeName": "Buttons", + "props": { + "buttons": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Plan a Trip to Paris", + "action": { + "type": "continue_conversation", + "context": "Help me plan a trip to Paris" + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btn1" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Best Hotels in Paris", + "action": { + "type": "continue_conversation", + "context": "Show me the best hotels in Paris" + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btn2" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Build a Paris Itinerary", + "action": { + "type": "continue_conversation", + "context": "Build a 5-day Paris itinerary for me" + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btn3" + } + ], + "direction": "row" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "actionBtns" + } + ], + "sources": [ + { + "title": "Paris Travel Guide 2025", + "sourceName": "Travel and Tour World", + "url": "https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/" + }, + { + "title": "Best Things to Do in Paris 2026", + "sourceName": "Time Out Paris", + "url": "http://www.timeout.fr/paris/en/for-tourists" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "chat-example-2", + "schema": "chat", + "input": "Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "CardHeader", + "props": { + "title": "Analytics Dashboard", + "subtitle": "April 2026 · Business Performance Overview" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "pageHeader" + }, + { + "type": "element", + "typeName": "SnippetCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "total-revenue", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "circle-dollar-sign", + "category": "finance" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Total Revenue", + "subtitle": "Month to date", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "$284,500", + "subtext": "+12.4%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1" + }, + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "active-users", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "users", + "category": "people" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Active Users", + "subtitle": "Monthly active users", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "47,320", + "subtext": "+6.8%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2" + }, + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "conversion-rate", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "trending-up", + "category": "charts" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Conversion Rate", + "subtitle": "Avg. this month", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "5.7%", + "subtext": "+0.9%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3" + }, + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "churn-rate", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "user-minus", + "category": "people" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi4icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Churn Rate", + "subtitle": "Monthly customer churn", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi4lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "2.1%", + "subtext": "-0.4%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi4rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi4" + } + ], + "layout": "grid", + "responsive": true + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpiBlock" + }, + { + "type": "element", + "typeName": "SectionBlock", + "props": { + "sections": [ + { + "type": "element", + "typeName": "SectionItem", + "props": { + "value": "users", + "trigger": "User Activity", + "content": [ + { + "type": "element", + "typeName": "Tabs", + "props": { + "items": [ + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "growth", + "trigger": "User Growth", + "content": [ + { + "type": "element", + "typeName": "LineChart", + "props": { + "labels": [ + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + "Jan", + "Feb", + "Mar", + "Apr" + ], + "series": [ + { + "type": "element", + "typeName": "Series", + "props": { + "category": "DAU", + "values": [ + 5.1, + 5.4, + 5.8, + 6.2, + 6.7, + 7.1, + 7.6, + 8, + 8.4, + 8.9, + 9.3, + 9.8 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "dauSeries" + }, + { + "type": "element", + "typeName": "Series", + "props": { + "category": "MAU", + "values": [ + 28.4, + 30.1, + 31.8, + 33.5, + 35.2, + 37.1, + 38.8, + 40.4, + 42.1, + 43.9, + 45.6, + 47.3 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "mauSeries" + } + ], + "variant": "natural", + "xLabel": "Month", + "yLabel": "Users (k)" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "growthChart" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabGrowth" + }, + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "retention", + "trigger": "Cohort Retention", + "content": [ + { + "type": "element", + "typeName": "LineChart", + "props": { + "labels": [ + "Month 0", + "Month 1", + "Month 2", + "Month 3", + "Month 4", + "Month 5", + "Month 6" + ], + "series": [ + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Jan Cohort", + "values": [ + 100, + 80, + 70, + 62, + 56, + 51, + 47 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "cohortJan" + }, + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Feb Cohort", + "values": [ + 100, + 83, + 73, + 65, + 59, + 54, + 50 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "cohortFeb" + }, + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Mar Cohort", + "values": [ + 100, + 86, + 76, + 68, + 62, + 0, + 0 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "cohortMar" + } + ], + "variant": "natural", + "xLabel": "Month Since Signup", + "yLabel": "Retention (%)" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "retentionChart" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabRetention" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "userTabs" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "secUsers" + }, + { + "type": "element", + "typeName": "SectionItem", + "props": { + "value": "channels", + "trigger": "Acquisition Channels", + "content": [ + { + "type": "element", + "typeName": "Tabs", + "props": { + "items": [ + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "channel-bar", + "trigger": "Revenue by Channel", + "content": [ + { + "type": "element", + "typeName": "HorizontalBarChart", + "props": { + "labels": [ + "Organic Search", + "Paid Ads", + "Referral Program", + "Partner Network", + "Direct / Brand", + "Email Campaigns" + ], + "series": [ + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Revenue ($k)", + "values": [ + 82.4, + 68.1, + 54.6, + 38.2, + 26.8, + 14.4 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "channelSeries" + } + ], + "variant": "grouped", + "xLabel": "Revenue ($k)", + "yLabel": "Channel" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "channelBarChart" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabChannelBar" + }, + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "channel-table", + "trigger": "Full Breakdown", + "content": [ + { + "type": "element", + "typeName": "Table", + "props": { + "columns": [ + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Channel", + "data": [ + "Organic Search", + "Paid Ads", + "Referral Program", + "Partner Network", + "Direct / Brand", + "Email Campaigns" + ], + "type": "string" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "colChannel" + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Leads", + "data": [ + 4210, + 3180, + 2050, + 1120, + 1290, + 820 + ], + "type": "number" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "colLeads" + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Conv. Rate", + "data": [ + "6.4%", + "5.1%", + "9.4%", + "11.8%", + "5.8%", + "8.1%" + ], + "type": "string" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "colConv" + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "CAC ($)", + "data": [ + 188, + 395, + 132, + 109, + 218, + 154 + ], + "type": "number" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "colCac" + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Revenue ($k)", + "data": [ + 82.4, + 68.1, + 54.6, + 38.2, + 26.8, + 14.4 + ], + "type": "number" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "colRevenue" + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Status", + "data": [ + "Scaling", + "Optimizing", + "Scaling", + "Growing", + "Stable", + "Stable" + ], + "type": "string" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "colStatus" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "channelTable" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabChannelTable" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "channelTabs" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "secChannels" + } + ], + "isFoldable": false + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "sections" + }, + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "Support Health & Marketing ROI", + "description": "Click a card to explore deeper insights" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "deepDiveHeader" + }, + { + "type": "element", + "typeName": "CompositeCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "CompositeCardItem", + "props": { + "id": "support-health", + "header": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "headphones", + "category": "communication" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "supportIcon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Support Health", + "subtitle": "Ticket volume & resolution trends", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "supportHeader" + }, + "body": [ + { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "94.2% CSAT", + "subtext": "Customer Satisfaction Score", + "trend": { + "direction": "up", + "value": 2.1 + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "supportMetric" + }, + { + "type": "element", + "typeName": "BarChart", + "props": { + "labels": [ + "Jan", + "Feb", + "Mar", + "Apr" + ], + "series": [ + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Opened", + "values": [ + 341, + 327, + 308, + 289 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "openSeries" + }, + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Resolved", + "values": [ + 319, + 318, + 301, + 283 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "resolvedSeries" + } + ], + "variant": "grouped", + "xLabel": "Month", + "yLabel": "Tickets" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "supportChart" + }, + { + "type": "element", + "typeName": "EntityList", + "props": { + "rows": [ + { + "left": "Avg. Resolution Time", + "right": "4h 12m", + "rightVariant": "text" + }, + { + "left": "First Contact Resolution", + "right": "78.4%", + "rightVariant": "number" + }, + { + "left": "Escalation Rate", + "right": "6.2%", + "rightVariant": "number" + } + ], + "size": "small" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "supportList" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "cardSupport" + }, + { + "type": "element", + "typeName": "CompositeCardItem", + "props": { + "id": "marketing-roi", + "header": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "megaphone", + "category": "communication" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "marketingIcon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Marketing ROI", + "subtitle": "Spend vs. pipeline generated", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "marketingHeader" + }, + "body": [ + { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "3.8x Blended ROI", + "subtext": "Return on Ad Spend", + "trend": { + "direction": "up", + "value": 0.4 + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "marketingMetric" + }, + { + "type": "element", + "typeName": "AreaChart", + "props": { + "labels": [ + "Jan", + "Feb", + "Mar", + "Apr" + ], + "series": [ + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Ad Spend", + "values": [ + 44, + 46.8, + 49.2, + 51.6 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "spendSeries" + }, + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Pipeline Generated", + "values": [ + 158.2, + 171.5, + 184.9, + 196.1 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "pipelineSeries" + } + ], + "variant": "natural", + "xLabel": "Month", + "yLabel": "Value ($k)" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "marketingChart" + }, + { + "type": "element", + "typeName": "EntityList", + "props": { + "rows": [ + { + "left": "Total Ad Spend (Apr)", + "right": "$51,600", + "rightVariant": "number" + }, + { + "left": "Cost per Lead", + "right": "$48.20", + "rightVariant": "number" + }, + { + "left": "Top Channel", + "right": "Organic Search", + "rightVariant": "text" + } + ], + "size": "small" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "marketingList" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "cardMarketing" + } + ], + "layout": "grid", + "responsive": true, + "action": { + "type": "continue_conversation", + "context": "Explore this deep-dive area in more detail" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "compositeCards" + }, + { + "type": "element", + "typeName": "Buttons", + "props": { + "buttons": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Break Down by Channel", + "action": { + "type": "continue_conversation", + "context": "Break down this month's revenue by acquisition channel" + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btnChannels" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Forecast Next Quarter", + "action": { + "type": "continue_conversation", + "context": "Forecast revenue and active users for next quarter" + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btnForecast" + } + ], + "direction": "row" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "actionButtons" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "chat-example-3", + "schema": "chat", + "input": "Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "CardHeader", + "props": { + "title": "Plan Your Trip", + "subtitle": "A few ideas to spark inspiration — then tell me your preferences" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "header" + }, + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Tap a style to jump straight in, or fill the quick form below for a tailored plan." + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "intro" + }, + { + "type": "element", + "typeName": "VisualCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Tropical Beach Escape", + "subtext": "Overwater villas & snorkeling", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp1body" + }, + "id": "inspo-beach", + "bgImageSrc": "https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "Relaxation", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "umbrella", + "category": "travel" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp1icon" + }, + "size": "sm", + "variant": "info" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp1tag" + }, + "bgImageAlt": "Maldives overwater villas" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp1" + }, + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Mountain Adventure", + "subtext": "Trekking & epic views", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp2body" + }, + "id": "inspo-mountain", + "bgImageSrc": "https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "Active", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "mountain", + "category": "nature" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp2icon" + }, + "size": "sm", + "variant": "warning" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp2tag" + }, + "bgImageAlt": "Trekking in the Peruvian Andes" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "insp2" + } + ], + "layout": "grid", + "responsive": true, + "action": { + "type": "continue_conversation", + "context": "Plan me a trip in this style with destinations, itinerary, and costs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "inspoCards" + }, + { + "type": "element", + "typeName": "Form", + "props": { + "name": "trip-planner", + "buttons": { + "type": "element", + "typeName": "Buttons", + "props": { + "buttons": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Plan My Trip", + "action": { + "type": "continue_conversation", + "context": "Help me plan a trip based on my form submission" + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btnSubmit" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Just Surprise Me", + "action": { + "type": "continue_conversation", + "context": "Skip the form and surprise me with a destination and itinerary" + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "btnSkip" + } + ], + "direction": "row" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "formButtons" + }, + "fields": [ + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Destination", + "input": { + "type": "element", + "typeName": "Input", + "props": { + "name": "destination", + "placeholder": "e.g. Tokyo, Japan — or leave blank", + "type": "text" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "destinationInput" + }, + "hint": "Leave blank if you'd like suggestions" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcDestination" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Travel Dates", + "input": { + "type": "element", + "typeName": "DatePicker", + "props": { + "name": "travel-dates", + "mode": "range", + "rules": { + "required": true + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "datesPicker" + }, + "hint": "Select your start and end dates" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcDates" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Number of Travellers", + "input": { + "type": "element", + "typeName": "Select", + "props": { + "name": "num-travellers", + "items": [ + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "1", + "label": "1 — Solo" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tr1" + }, + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "2", + "label": "2 — Couple" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tr2" + }, + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "3-4", + "label": "3–4 People" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tr3" + }, + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "5+", + "label": "5+ People" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tr4" + } + ], + "placeholder": "Select number of travellers", + "rules": { + "required": true + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "travellersSelect" + }, + "hint": "How many people are travelling?" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcTravellers" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Trip Type", + "input": { + "type": "element", + "typeName": "OptionCards", + "props": { + "name": "trip-type", + "type": "single", + "items": [ + { + "type": "element", + "typeName": "OptionCard", + "props": { + "value": "adventure", + "title": "Adventure", + "subtitle": "Hiking, trekking & outdoor activities", + "topContent": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "mountain", + "category": "nature" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc1icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc1" + }, + { + "type": "element", + "typeName": "OptionCard", + "props": { + "value": "beach", + "title": "Beach & Relaxation", + "subtitle": "Sun, sand & leisure", + "topContent": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "waves", + "category": "nature" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc2icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc2" + }, + { + "type": "element", + "typeName": "OptionCard", + "props": { + "value": "cultural", + "title": "Cultural & Historical", + "subtitle": "Museums, heritage & local experiences", + "topContent": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "landmark", + "category": "buildings" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc3icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc3" + }, + { + "type": "element", + "typeName": "OptionCard", + "props": { + "value": "city", + "title": "City Break", + "subtitle": "Urban exploration & nightlife", + "topContent": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "building-2", + "category": "buildings" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc4icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "oc4" + } + ], + "rules": { + "required": true + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tripTypeCards" + }, + "hint": "What kind of trip are you planning?" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcTripType" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Estimated Budget (per person)", + "input": { + "type": "element", + "typeName": "Slider", + "props": { + "name": "budget", + "variant": "discrete", + "min": 500, + "max": 10000, + "step": 500, + "defaultValue": [ + 2500 + ], + "label": "Budget (USD)" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "budgetSlider" + }, + "hint": "Drag to set your per-person budget in USD" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcBudget" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Accommodation Preference", + "input": { + "type": "element", + "typeName": "Chips", + "props": { + "name": "accommodation", + "type": "multiple", + "items": [ + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "hotel", + "label": "Hotel", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "building", + "category": "buildings" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch1icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch1" + }, + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "resort", + "label": "Resort", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "umbrella", + "category": "travel" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch2icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch2" + }, + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "airbnb", + "label": "Vacation Rental", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "home", + "category": "home" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch3icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch3" + }, + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "camping", + "label": "Camping / Glamping", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "tent", + "category": "nature" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch4icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "ch4" + } + ], + "rules": {}, + "defaultValue": [ + "hotel" + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "stayChips" + }, + "hint": "Select all that apply" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcStay" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Special Requests or Notes", + "input": { + "type": "element", + "typeName": "TextArea", + "props": { + "name": "special-requests", + "placeholder": "e.g. vegetarian meals, wheelchair access, honeymoon surprise...", + "rows": 4 + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "notesArea" + }, + "hint": "Any dietary needs, accessibility requirements, or specific interests?" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fcNotes" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "form" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "chat-example-4", + "schema": "chat", + "input": "Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "CardHeader", + "props": { + "title": "Retro-Energetic Indian Tracks", + "subtitle": "New Hindi releases with 80s/90s dance DNA" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "header" + }, + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video." + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "intro" + }, + { + "type": "element", + "typeName": "VisualCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Tamma Tamma", + "subtext": "Dhurandhar · Ranveer Singh", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v1body" + }, + "id": "tamma", + "bgImageSrc": "https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "80s Electro-Disco", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "disc-3", + "category": "multimedia" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v1icon" + }, + "size": "sm", + "variant": "success" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v1tag" + }, + "bgImageAlt": "Tamma Tamma video poster" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v1" + }, + { + "type": "element", + "typeName": "VisualCardItem", + "props": { + "body": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "Sajan Re", + "subtext": "Nora Fatehi · Badshah", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v2body" + }, + "id": "sajan", + "bgImageSrc": "https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg", + "tag": { + "type": "element", + "typeName": "Tag", + "props": { + "text": "Synthwave Electro", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "music", + "category": "multimedia" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v2icon" + }, + "size": "sm", + "variant": "info" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v2tag" + }, + "bgImageAlt": "Sajan Re video poster" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "v2" + } + ], + "layout": "grid", + "responsive": true, + "action": { + "type": "continue_conversation", + "context": "Tell me more about this track and its retro influences" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "posters" + }, + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "Watch the Exact Videos", + "description": "Each button opens that track's official video" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "linksHeader" + }, + { + "type": "element", + "typeName": "CompositeCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "CompositeCardItem", + "props": { + "id": "t-tamma", + "header": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "disc-3", + "category": "multimedia" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Tamma Tamma", + "subtitle": "Bappi Lahiri classic, electro-funk rework", + "bold": true, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1h" + }, + "body": [ + { + "type": "element", + "typeName": "Text", + "props": { + "variant": "text", + "value": "Heavy analog synths and brass over a fast disco groove.", + "subtext": "Retro Electro-Disco", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1body" + }, + { + "type": "element", + "typeName": "TagBlock", + "props": { + "tags": [ + "2026 Film Hit", + "Peak Party" + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1tags" + } + ], + "footer": { + "button": { + "type": "element", + "typeName": "Button", + "props": { + "label": "Watch on YouTube", + "action": { + "type": "open_url", + "url": "https://www.youtube.com/watch?v=PQHeOb0Q9oo" + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1btn" + } + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t1" + }, + { + "type": "element", + "typeName": "CompositeCardItem", + "props": { + "id": "t-sajan", + "header": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "music", + "category": "multimedia" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t2icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Sajan Re", + "subtitle": "Nora Fatehi · Badshah · Sanjoy", + "bold": true, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t2h" + }, + "body": [ + { + "type": "element", + "typeName": "Text", + "props": { + "variant": "text", + "value": "Synthwave melody hooks over a modern club beat.", + "subtext": "Retro-Fusion Electro", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t2body" + }, + { + "type": "element", + "typeName": "TagBlock", + "props": { + "tags": [ + "Club Anthem", + "Nora x Badshah" + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t2tags" + } + ], + "footer": { + "button": { + "type": "element", + "typeName": "Button", + "props": { + "label": "Watch on YouTube", + "action": { + "type": "open_url", + "url": "https://www.youtube.com/watch?v=COUSCnFazzc" + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t2btn" + } + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t2" + } + ], + "layout": "grid", + "responsive": true + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "trackCards" + } + ], + "sources": [ + { + "title": "Tamma Tamma (Full Video) - Dhurandhar", + "sourceName": "YouTube (T-Series)", + "url": "https://www.youtube.com/watch?v=PQHeOb0Q9oo" + }, + { + "title": "Sajan Re (Official Music Video)", + "sourceName": "YouTube (T-Series)", + "url": "https://www.youtube.com/watch?v=COUSCnFazzc" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "chat-example-5", + "schema": "chat", + "input": "Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Top Languages", + "size": "large-heavy" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "title" + }, + { + "type": "element", + "typeName": "Table", + "props": { + "columns": [ + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Language", + "data": [ + "Python", + "JavaScript", + "Java" + ] + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Users (M)", + "data": [ + 15.7, + 14.2, + 12.1 + ] + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Year", + "data": [ + 1991, + 1995, + 1995 + ] + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tbl" + }, + { + "type": "element", + "typeName": "FollowUpBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "FollowUpItem", + "props": { + "text": "Tell me more about Python" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fu1" + }, + { + "type": "element", + "typeName": "FollowUpItem", + "props": { + "text": "Show me a JavaScript comparison" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fu2" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "followUps" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "operators", + "schema": "test", + "input": "$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "yes" + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "member-index", + "schema": "test", + "input": "$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "b" + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": [ + "a", + "b" + ] + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": 1 + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "actions", + "schema": "test", + "input": "$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Inc", + "action": { + "steps": [ + { + "type": "set", + "target": "$n", + "valueAST": { + "k": "BinOp", + "op": "+", + "left": { + "k": "StateRef", + "n": "$n" + }, + "right": { + "k": "Num", + "v": 1 + } + } + }, + { + "type": "continue_conversation", + "message": "Bumped", + "context": "ctx" + } + ] + } + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "b1" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Reset", + "action": { + "steps": [ + { + "type": "reset", + "targets": [ + "$n" + ] + } + ] + } + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "b2" + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Docs", + "action": { + "steps": [ + { + "type": "open_url", + "url": "https://openui.com" + } + ] + } + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "b3" + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "each", + "schema": "test", + "input": "$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "a" + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": "b" + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "builtins-all", + "schema": "test", + "input": "$n = [5, \"3\", 9, \"x\", true]\n$rows = [{n: \"b\", v: 2}, {n: \"a\", v: 10}, {n: \"c\", v: \"1\"}]\nroot = Card([Text(\"\" + @Count($n) + \"|\" + @Sum($n) + \"|\" + @Avg($n) + \"|\" + @Min($n) + \"|\" + @Max($n) + \"|\" + @First($n) + \"|\" + @Last($n) + \"|\" + @Round(-2.5) + \"|\" + @Round(1.005, 2) + \"|\" + @Abs(-3) + \"|\" + @Floor(1.7) + \"|\" + @Ceil(1.2)), Text(@Sort($rows, \"v\", \"desc\").n + \"\"), Text(@Sort($rows, \"n\").n + \"\"), Text(@Filter($rows, \"v\", \">\", 1).n + \"\"), Text(@Filter($rows, \"n\", \"contains\", \"a\").n + \"\"), Text(@Filter($rows, \"v\", \"==\", \"2\").n + \"\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "5|18|3.6|0|9|5|true|-2|1|3|1|2" + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": "a,b,c" + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": "a,b,c" + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": "b,a" + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": "a" + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Text", + "props": { + "text": "b" + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "arithmetic-edges", + "schema": "test", + "input": "$z = 0\nroot = Card([Text(\"\" + (5 / $z) + \"|\" + (-7 % 3) + \"|\" + (7 % $z) + \"|\" + (\"a\" + null) + \"|\" + (null + 1) + \"|\" + (true + 1) + \"|\" + (\"5\" * \"2\") + \"|\" + (\"x\" - 1) + \"|\" + (0.1 + 0.2) + \"|\" + (1 / 3))])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "0|-1|0|a|1|2|10|-1|0.30000000000000004|0.3333333333333333" + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "truthiness-and-equality", + "schema": "test", + "input": "$e = \"\"\n$z = 0\n$arr = []\nroot = Card([Text(\"\" + ($e || \"empty\") + \"|\" + ($z && \"no\") + \"|\" + ($arr ? \"arr-truthy\" : \"arr-falsy\") + \"|\" + (1 == \"1\") + \"|\" + (null == 0) + \"|\" + ($missing == null) + \"|\" + !$e)])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "empty|0|arr-truthy|true|false|true|true" + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "ternary-components", + "schema": "test", + "input": "$on = true\nroot = Card([$on ? Text(\"on\", \"l\") : Button(\"off\"), $on ? null : Text(\"hidden\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "on", + "size": "l" + }, + "partial": false, + "hasDynamicProps": true + }, + null + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "ternary-components-off", + "schema": "test", + "input": "$on = true\nroot = Card([$on ? Text(\"on\", \"l\") : Button(\"off\")])", + "state": { + "$on": false + }, + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "off" + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "state-override", + "schema": "test", + "input": "$count = 1\nroot = Card([Text(\"count \" + $count)])", + "state": { + "$count": 41 + }, + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "count 41" + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "reactive-binding", + "schema": "test", + "input": "$v = \"hi\"\nroot = Card([Input(\"name\", $v), Input(\"plain\", \"x\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Input", + "props": { + "name": "name", + "value": { + "__reactive": "assign", + "target": "$v", + "expr": { + "k": "StateRef", + "n": "$value" + } + } + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Input", + "props": { + "name": "plain", + "value": "x" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "reactive-assign", + "schema": "test", + "input": "$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Input", + "props": { + "name": "name", + "value": { + "__reactive": "assign", + "target": "$v", + "expr": { + "k": "StateRef", + "n": "$value" + } + } + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "query-results", + "schema": "test", + "input": "$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])", + "queryResults": { + "users": { + "rows": [ + { + "id": 1 + }, + { + "id": 2 + } + ] + }, + "save": { + "status": "idle" + } + }, + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "2 users" + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Save", + "action": { + "steps": [ + { + "type": "run", + "statementId": "save", + "refType": "mutation" + }, + { + "type": "run", + "statementId": "users", + "refType": "query" + } + ] + } + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "each-actions", + "schema": "test", + "input": "$items = [{id: 1, t: \"a\"}, {id: 2, t: \"b\"}]\n$sel = 0\nroot = Card(@Each($items, it, Button(it.t, Action([@Set($sel, it.id), @ToAssistant(\"Pick \" + it.t)]))))", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "a", + "action": { + "steps": [ + { + "type": "set", + "target": "$sel", + "valueAST": { + "k": "Num", + "v": 1 + } + }, + { + "type": "continue_conversation", + "message": "Pick a" + } + ] + } + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "b", + "action": { + "steps": [ + { + "type": "set", + "target": "$sel", + "valueAST": { + "k": "Num", + "v": 2 + } + }, + { + "type": "continue_conversation", + "message": "Pick b" + } + ] + } + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + } +] diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json index f6732fec6e..86f0a2e322 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json @@ -4220,7 +4220,36 @@ } } }, - "root": "Card" + "root": "Card", + "reactive": { + "Callout": [ + "visible" + ], + "Input": [ + "value" + ], + "TextArea": [ + "value" + ], + "Select": [ + "value" + ], + "DatePicker": [ + "value" + ], + "Slider": [ + "value" + ], + "CheckBoxGroup": [ + "value" + ], + "RadioGroup": [ + "value" + ], + "SwitchGroup": [ + "value" + ] + } }, "test": { "schema": { @@ -4358,6 +4387,11 @@ } } }, - "root": "Card" + "root": "Card", + "reactive": { + "Input": [ + "value" + ] + } } } diff --git a/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift b/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift new file mode 100644 index 0000000000..3d59003ef2 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift @@ -0,0 +1,134 @@ +import Testing + +@testable import OpenUILang + +@MainActor +@Suite struct QueryManagerTests { + /// Waits for in-flight tool calls to settle. + func settle() async { + for _ in 0..<20 { await Task.yield() } + } + + @Test func fetchesQueriesAndFallsBackToDefaults() async { + let provider = FunctionToolProvider([ + "list_users": { args in ["rows": [["name": args["q"] ?? .null]]] } + ]) + let manager = QueryManager(toolProvider: provider) + let node = QueryNode( + statementId: "users", toolName: "list_users", args: ["q": "ada"], defaults: ["rows": []], + refreshInterval: nil, deps: nil, complete: true) + + manager.evaluateQueries([node]) + #expect(manager.result("users") == ["rows": []]) + #expect(manager.isLoading("users")) + + await settle() + #expect(manager.result("users") == ["rows": [["name": "ada"]]]) + #expect(!manager.isAnyLoading) + #expect(manager.result("unknown") == .null) + } + + @Test func reportsMissingTools() async { + let manager = QueryManager(toolProvider: FunctionToolProvider(["other": { _ in .null }])) + manager.evaluateQueries([ + QueryNode( + statementId: "q", toolName: "nope", args: [:], defaults: .null, refreshInterval: nil, + deps: nil, complete: true) + ]) + await settle() + #expect(manager.snapshot.errors.first?.code == "tool-not-found") + #expect(manager.snapshot.errors.first?.hint == "Available tools: other") + } + + @Test func mutationSuccessAndFailure() async { + let provider = FunctionToolProvider([ + "save": { args in ["saved": args["name"] ?? .null] }, + "fail": { _ in throw McpToolError(toolErrorText: "nope") }, + ]) + let manager = QueryManager(toolProvider: provider) + manager.registerMutations([ + MutationNode(statementId: "save", toolName: "save"), + MutationNode(statementId: "boom", toolName: "fail"), + ]) + #expect(manager.mutationResult("save") == ["status": "idle"]) + + #expect(await manager.fireMutation("save", args: ["name": "ada"])) + #expect(manager.mutationResult("save") == ["status": "success", "data": ["saved": "ada"]]) + + #expect(await manager.fireMutation("boom", args: [:]) == false) + #expect(manager.mutationResult("boom")?["status"] == "error") + #expect(manager.snapshot.errors.first?.code == "mcp-error") + } + + @Test func failedMutationHaltsTheActionPlan() async { + let provider = FunctionToolProvider(["fail": { _ in throw ToolNotFoundError(toolName: "x") }]) + let runtime = OpenUIRuntime(library: FixtureLibrary(schemaName: "test"), toolProvider: provider) + var events: [ActionEvent] = [] + runtime.onAction = { events.append($0) } + runtime.update( + response: """ + save = Mutation("fail", {}) + root = Card([Button("Save", Action([@Run(save), @ToAssistant("Saved")]))]) + """, isStreaming: false) + let action = runtime.evaluatedRoot()?.props["children"]?.arrayValue?.first?.elementValue? + .props["action"] + + await runtime.triggerAction("Save", action: action) + #expect(events.isEmpty) + } + + @Test func extractsMcpResults() throws { + #expect( + try extractToolResult(["content": [["type": "text", "text": "{\"a\":1}"]]]) == ["a": 1]) + #expect(try extractToolResult(["content": [["type": "text", "text": "plain"]]]) == "plain") + #expect(try extractToolResult(["structuredContent": ["b": 2], "content": []]) == ["b": 2]) + #expect(throws: McpToolError.self) { + try extractToolResult(["isError": true, "content": [["type": "text", "text": "bad"]]]) + } + } +} + +@Suite struct FormRulesTests { + @Test func parsesRules() { + #expect(parseRule("min:8") == ParsedRule(type: "min", arg: 8)) + #expect(parseRule("pattern:^[a-z]:x") == ParsedRule(type: "pattern", arg: "^[a-z]:x")) + #expect(parseRule("minLength:abc") == ParsedRule(type: "minLength", arg: "abc")) + #expect( + parseStructuredRules(["required": true, "email": false, "max": 5, "min": .null]) + == [ParsedRule(type: "required"), ParsedRule(type: "max", arg: 5)]) + } + + @Test func builtInMessages() { + let cases: [(OpenUIValue, [ParsedRule], String?)] = [ + ("", [ParsedRule(type: "required")], "This field is required"), + (["value": ""], [ParsedRule(type: "required")], "This field is required"), + ( + ["a": false, "b": false], [ParsedRule(type: "required")], "At least one option is required" + ), + ("ada@x.io", [ParsedRule(type: "email")], nil), + ("ada@x", [ParsedRule(type: "email")], "Please enter a valid email"), + ("https://openui.com", [ParsedRule(type: "url")], nil), + ("openui.com", [ParsedRule(type: "url")], "Please enter a valid URL"), + ("12px", [ParsedRule(type: "numeric")], nil), + ("abc", [ParsedRule(type: "numeric")], "Must be a number"), + ("3", [ParsedRule(type: "min", arg: 5)], "Must be at least 5"), + (11, [ParsedRule(type: "max", arg: 10.5)], "Must be no more than 10.5"), + ("ab", [ParsedRule(type: "minLength", arg: 3)], "Must be at least 3 characters"), + ("😀😀", [ParsedRule(type: "maxLength", arg: 3)], "Must be no more than 3 characters"), + ("abc", [ParsedRule(type: "pattern", arg: "^[0-9]+$")], "Invalid format"), + ( + "x", [ParsedRule(type: "unknownRule"), ParsedRule(type: "minLength", arg: 2)], + "Must be at least 2 characters" + ), + ] + for (value, rules, expected) in cases { + #expect(validate(value, rules) == expected, "\(value) \(rules)") + } + } + + @Test func customValidatorsWin() { + let custom: [String: ValidatorFn] = ["required": { _, _ in "custom" }] + #expect( + validate("filled", [ParsedRule(type: "required")], customValidators: custom) == "custom") + } +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/RuntimeTests.swift b/packages/swift-lang/Tests/OpenUILangTests/RuntimeTests.swift new file mode 100644 index 0000000000..5de62d2754 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/RuntimeTests.swift @@ -0,0 +1,167 @@ +import Testing + +@testable import OpenUILang + +/// A library built straight from the test fixture schema. +struct FixtureLibrary: ComponentLibrary { + let schemaName: String + var paramMap: ParamMap { Fixtures.paramMap(schemaName) } + var rootName: String? { Fixtures.rootName(schemaName) } + func isReactiveProp(_ component: String, _ prop: String) -> Bool { + Fixtures.schemaContext(schemaName).isReactiveProp(component, prop) + } +} + +@MainActor +@Suite struct RuntimeTests { + func makeRuntime(_ schema: String = "test", initialState: OpenUIObject? = nil) -> OpenUIRuntime { + OpenUIRuntime(library: FixtureLibrary(schemaName: schema), initialState: initialState) + } + + @Test func streamsAndSeedsStateFromDeclarations() { + let runtime = makeRuntime() + runtime.update(response: "$count = 3\nroot = Card([Text(\"n \" + $co", isStreaming: true) + #expect(runtime.parseResult?.meta.incomplete == true) + #expect(runtime.store.get("$count") == 3) + + runtime.update(response: "$count = 3\nroot = Card([Text(\"n \" + $count)])", isStreaming: false) + #expect( + runtime.evaluatedRoot()?.props["children"]?.arrayValue?.first?.elementValue? + .props["text"] == "n 3") + } + + @Test func keepsUserChangesWhenDeclarationsChange() { + let runtime = makeRuntime() + runtime.update(response: "$name = \"\"\nroot = Card([Text($name)])", isStreaming: true) + runtime.store.set("$name", "Ada") + // A new declaration arrives while streaming; the user's value must survive. + runtime.update( + response: "$name = \"\"\n$other = 1\nroot = Card([Text($name)])", isStreaming: false) + #expect(runtime.store.get("$name") == "Ada") + #expect(runtime.store.get("$other") == 1) + } + + @Test func initialStateSplitsBindingsAndFormData() { + let runtime = makeRuntime(initialState: ["$name": "Restored", "contact": ["email": "a@b.co"]]) + runtime.update(response: "$name = \"\"\nroot = Card([Text($name)])", isStreaming: false) + #expect(runtime.store.get("$name") == "Restored") + #expect(runtime.store.get("contact") == ["email": "a@b.co"]) + } + + @Test func runsActionPlanSteps() async { + let runtime = makeRuntime() + var events: [ActionEvent] = [] + runtime.onAction = { events.append($0) } + runtime.update( + response: """ + $n = 1 + root = Card([b]) + b = Button("Go", Action([@Set($n, $n + 1), @ToAssistant("Bumped", "ctx"), @OpenUrl("https://openui.com")])) + """, isStreaming: false) + let action = runtime.evaluatedRoot()?.props["children"]?.arrayValue?.first?.elementValue? + .props["action"] + + await runtime.triggerAction("Go", action: action) + + #expect(runtime.store.get("$n") == 2) + #expect(events.map(\.type) == ["continue_conversation", "open_url"]) + #expect(events[0].humanFriendlyMessage == "Bumped") + #expect(events[0].params == ["context": "ctx"]) + #expect(events[1].params == ["url": "https://openui.com"]) + + await runtime.triggerAction( + "Reset", action: .actionPlan(ActionPlan(steps: [.reset(targets: ["$n"])]))) + #expect(runtime.store.get("$n") == 1) + } + + @Test func plainAndLegacyActionsContinueTheConversation() async { + let runtime = makeRuntime() + var events: [ActionEvent] = [] + runtime.onAction = { events.append($0) } + runtime.update(response: "root = Card([Text(\"x\")])", isStreaming: false) + + await runtime.triggerAction("Send it") + await runtime.triggerAction( + "Docs", action: ["type": "open_url", "url": "https://openui.com", "params": ["a": 1]]) + + #expect(events[0].type == "continue_conversation") + #expect(events[0].humanFriendlyMessage == "Send it") + #expect(events[1].type == "open_url") + #expect(events[1].params == ["a": 1, "url": "https://openui.com"]) + } + + @Test func formFieldsAreWrappedAndPayloadIsScoped() async { + let runtime = makeRuntime() + var events: [ActionEvent] = [] + runtime.onAction = { events.append($0) } + runtime.update(response: "root = Card([Text(\"x\")])", isStreaming: false) + + runtime.setFieldValue(form: "contact", componentType: "Input", name: "email", value: "a@b.co") + #expect(runtime.fieldValue(form: "contact", name: "email") == "a@b.co") + #expect(runtime.store.get("contact")["email"] == ["value": "a@b.co", "componentType": "Input"]) + + await runtime.triggerAction("Submit", form: "contact") + #expect(events.first?.formName == "contact") + #expect(events.first?.formState?.keys == ["contact"]) + } + + @Test func reactiveBindingWritesState() { + let runtime = makeRuntime() + runtime.update( + response: + "$v = \"start\"\nroot = Card([Input(\"name\", $v), Input(\"upper\", $u = $value + \"!\")])", + isStreaming: false) + let inputs = runtime.evaluatedRoot()?.props["children"]?.arrayValue ?? [] + + let plain = runtime.stateField( + name: "name", binding: inputs[0].elementValue!.props["value"]!, form: nil) + #expect(plain.isReactive) + #expect(plain.value == "start") + plain.setValue("typed") + #expect(runtime.store.get("$v") == "typed") + + let derived = runtime.stateField( + name: "upper", binding: inputs[1].elementValue!.props["value"]!, form: nil) + derived.setValue("hey") + #expect(runtime.store.get("$u") == "hey!") + } + + /// lang-core nests the binding of a reactive input inside `@Each` four levels + /// deep, so typing writes `undefined` into the state. The Swift port keeps the + /// binding intact and writes the typed value. + @Test func reactiveBindingInsideEachWritesState() { + let runtime = makeRuntime("chat") + runtime.update( + response: """ + $items = ["a"] + $v = "start" + root = Card([Form("f", Buttons([Button("ok")]), @Each($items, it, FormControl("L", Input("n", "p", "text", null, $v))))]) + """, isStreaming: false) + let form = runtime.evaluatedRoot()?.props["children"]?.arrayValue?.first?.elementValue + let input = form?.props["fields"]?.arrayValue?.first?.elementValue?.props["input"]? + .elementValue + let binding = input?.props["value"] ?? .undefined + #expect(binding == .reactiveAssign(ReactiveAssign(target: "$v", expr: .stateRef("$value")))) + + runtime.stateField(name: "n", binding: binding, form: "f").setValue("typed") + #expect(runtime.store.get("$v") == "typed") + } + + @Test func stateUpdatesReachTheHostAfterInitialization() { + let runtime = makeRuntime() + var updates = 0 + runtime.onStateUpdate = { _ in updates += 1 } + runtime.update(response: "$n = 1\nroot = Card([Text(\"x\")])", isStreaming: false) + #expect(updates == 0) + runtime.store.set("$n", 2) + #expect(updates == 1) + } + + @Test func emptyResponseClearsTheResult() { + let runtime = makeRuntime() + runtime.update(response: "root = Card([Text(\"x\")])", isStreaming: false) + runtime.update(response: "", isStreaming: false) + #expect(runtime.parseResult == nil) + #expect(runtime.evaluatedRoot() == nil) + } +} From 331960414f878e2f863ccc5ce1528c7ad23c21a5 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Mon, 5 Oct 2026 03:41:05 +0530 Subject: [PATCH 03/52] feat(swift-lang): define component libraries and generate prompts in Swift Adds the library side of OpenUILang: - PropType/Prop/ComponentSchema to describe components with typed props, $binding props and defaults; schemas serialize to the same JSON Schema Zod's toJSONSchema produces, and signatures match buildSignature - Library, which compiles the parser's parameter map, answers binding lookups for evaluation, and exports a LibrarySpec a server can pass to lang-core's generateSystemPrompt - generatePrompt, a port of lang-core's prompt assembly Fixtures check the prompt text byte for byte against lang-core across option combinations (tools, bindings, edit and inline modes, groups), and check Swift-defined chat components against the Zod schemas. --- .../swift-lang/Scripts/generate-fixtures.mjs | 66 +- .../Sources/OpenUILang/Library.swift | 314 ++++ .../Sources/OpenUILang/Prompt.swift | 676 +++++++ .../OpenUILangTests/Fixtures/chat-spec.json | 538 ++++++ .../OpenUILangTests/Fixtures/prompts.json | 1634 +++++++++++++++++ .../PromptAndLibraryTests.swift | 178 ++ 6 files changed, 3405 insertions(+), 1 deletion(-) create mode 100644 packages/swift-lang/Sources/OpenUILang/Library.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Prompt.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/Fixtures/chat-spec.json create mode 100644 packages/swift-lang/Tests/OpenUILangTests/Fixtures/prompts.json create mode 100644 packages/swift-lang/Tests/OpenUILangTests/PromptAndLibraryTests.swift diff --git a/packages/swift-lang/Scripts/generate-fixtures.mjs b/packages/swift-lang/Scripts/generate-fixtures.mjs index 1897f71bd1..9e3f8fb235 100644 --- a/packages/swift-lang/Scripts/generate-fixtures.mjs +++ b/packages/swift-lang/Scripts/generate-fixtures.mjs @@ -347,6 +347,68 @@ const evalCases = [ const evalFixtures = evalCases.map((c) => ({ ...c, expected: evaluateCase(c) })); +// ── Prompts ─────────────────────────────────────────────────────────────── + +const chatSpec = ui.openuiChatLibrary.toSpec(); +delete chatSpec.schema; // already in schemas.json + +const tools = [ + "search_docs", + { + name: "list_tickets", + description: "Open support tickets", + inputSchema: { + type: "object", + properties: { status: { type: "string", enum: ["open", "closed"] }, limit: { type: "number" } }, + required: ["status"], + }, + outputSchema: { + type: "object", + properties: { + rows: { type: "array", items: { type: "object", properties: { id: { type: "string" } } } }, + total: { type: "integer" }, + }, + }, + }, + { name: "ping", inputSchema: {}, outputSchema: undefined }, +]; + +const smallSpec = { + components: { + Box: { signature: "Box(children: (Text | Box)[])", description: "A box" }, + Text: { signature: "Text(value: string, tone?: \"a\" | \"b\")" }, + }, +}; + +// A slice of the chat library that still exercises ActionExpression, +// $binding, groups and ungrouped components, to keep variant fixtures small. +const sliceNames = ["Card", "TextContent", "Button", "Buttons", "Form", "FormControl", "Input", "Select", "SelectItem", "Table", "Col"]; +const sliceSpec = { + root: chatSpec.root, + components: Object.fromEntries(sliceNames.map((n) => [n, chatSpec.components[n]])), + componentGroups: [ + { name: "Forms", components: ["Form", "FormControl", "Input", "Select", "SelectItem"], notes: ["- Forms note"] }, + { name: "Buttons", components: ["Button", "Buttons", "Missing"] }, + ], +}; + +const promptCases = [ + { name: "chat-default", spec: chatSpec }, + { name: "chat-options", spec: { ...chatSpec, ...ui.openuiChatPromptOptions } }, + { name: "slice-bindings", spec: { ...sliceSpec, bindings: true } }, + { name: "slice-tools", spec: { ...sliceSpec, tools, toolExamples: ['x = Query("list_tickets", {status: "open"}, {rows: []})'] } }, + { name: "slice-tools-no-bindings", spec: { ...sliceSpec, tools, bindings: false } }, + { + name: "slice-modes", + spec: { ...sliceSpec, editMode: true, inlineMode: true, preamble: "Custom preamble.", additionalRules: ["Be brief"], examples: ["a = 1"] }, + }, + { name: "slice-no-groups", spec: { ...sliceSpec, componentGroups: undefined } }, + { name: "small-no-root", spec: smallSpec }, + { name: "small-tools-only", spec: { ...smallSpec, toolCalls: true, bindings: false } }, +].map((c) => ({ ...c, expected: core.generatePrompt(c.spec) })); + +const chatComponentSpecs = chatSpec; + function write(name, data, indent = 1) { mkdirSync(fixtures, { recursive: true }); writeFileSync(join(fixtures, name), JSON.stringify(data, null, indent) + "\n"); @@ -357,7 +419,9 @@ write("parser.json", parserCases); write("streaming.json", streamingCases, 0); write("stream-set.json", setCases); write("evaluation.json", evalFixtures); +write("prompts.json", promptCases); +write("chat-spec.json", chatComponentSpecs); console.log( - `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set, ${evalFixtures.length} evaluation fixtures`, + `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set, ${evalFixtures.length} evaluation, ${promptCases.length} prompt fixtures`, ); diff --git a/packages/swift-lang/Sources/OpenUILang/Library.swift b/packages/swift-lang/Sources/OpenUILang/Library.swift new file mode 100644 index 0000000000..f97c0fe550 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Library.swift @@ -0,0 +1,314 @@ +/// The type of a component prop. Mirrors the Zod schemas lang-core libraries +/// are written with, and serializes to the same JSON Schema. +public indirect enum PropType: Sendable, Equatable { + case string + case number + case boolean + /// Unconstrained (`z.any()`). + case any + case enumeration([String]) + case literal(OpenUIValue) + case array(PropType) + /// A nested object (`z.object`). + case object([Prop]) + /// `Record`. + case record(PropType) + /// A reference to another component in the library. + case component(String) + case union([PropType]) + /// A type shown by name in signatures (like lang-core's `tagSchemaId`), + /// serialized as its underlying schema. + case named(String, PropType) + + /// The action prop type (`ActionExpression`): an `Action([...])` expression, + /// or one of the legacy action objects. + public static let actionExpression: PropType = .named( + "ActionExpression", + .union([ + .object([Prop("type", .literal("open_url")), Prop("url", .string)]), + .object([ + Prop("type", .literal("continue_conversation")), Prop("context", .string, .optional), + ]), + .object([Prop("type", .string), Prop("params", .record(.any), .optional)]), + ])) +} + +/// A component prop: its name, type, and whether it may be omitted. +public struct Prop: Sendable, Equatable { + public enum Presence: Sendable, Equatable { + case required + case optional + /// Filled with this value when missing (`.default(value)` in Zod). + case defaulted(OpenUIValue) + } + + public var name: String + public var type: PropType + public var presence: Presence + /// Binds two-way to a `$state` variable (lang-core's `reactive()`), shown as + /// `$binding` in signatures. + public var isBinding: Bool + public var description: String? + + public init( + _ name: String, _ type: PropType, _ presence: Presence = .required, binding: Bool = false, + description: String? = nil + ) { + self.name = name + self.type = type + self.presence = presence + self.isBinding = binding + self.description = description + } + + /// Optional in signatures: `.optional` and `.defaulted` props may be omitted. + public var isOptional: Bool { presence != .required } + + /// Listed in the JSON Schema's `required`: Zod treats defaulted props as + /// required in its output schema. + var isSchemaRequired: Bool { presence != .optional } + + var defaultValue: OpenUIValue? { + if case .defaulted(let value) = presence { return value } + return nil + } +} + +/// A component's contract with the model: name, description and props in +/// positional order. Independent of how any UI layer renders it. +public struct ComponentSchema: Sendable, Equatable { + public var name: String + public var description: String + public var props: [Prop] + + public init(_ name: String, description: String, props: [Prop]) { + self.name = name + self.description = description + self.props = props + } + + /// The prompt signature, e.g. `TextContent(text: string, size?: "small" | "large")`. + public var signature: String { + let params = props.map { prop in + let type = typeAnnotation(prop.type, binding: prop.isBinding) + return prop.isOptional ? "\(prop.name)?: \(type)" : "\(prop.name): \(type)" + } + return "\(name)(\(params.joined(separator: ", ")))" + } + + /// This component's entry in the library JSON Schema's `$defs`. + public var jsonSchema: OpenUIValue { + var schema = objectSchema(props).objectValue! + if !description.isEmpty { schema["description"] = .string(description) } + return .object(schema) + } +} + +/// A library component: its schema plus how a UI layer renders it. +public struct ComponentDefinition { + public var schema: ComponentSchema + public var content: Content + + public init(_ schema: ComponentSchema, content: Content) { + self.schema = schema + self.content = content + } + + public var name: String { schema.name } +} + +// MARK: - Signatures + +private func typeAnnotation(_ type: PropType, binding: Bool) -> String { + let base = baseTypeAnnotation(type) + return binding ? "$binding<\(base)>" : base +} + +private func baseTypeAnnotation(_ type: PropType) -> String { + switch type { + case .named(let name, _), .component(let name): + return name + case .union(let options): + return options.isEmpty + ? "any" : options.map { typeAnnotation($0, binding: false) }.joined(separator: " | ") + case .array(let inner): + let innerType = typeAnnotation(inner, binding: false) + if case .union = inner { return "(\(innerType))[]" } + return "\(innerType)[]" + case .string: return "string" + case .number: return "number" + case .boolean: return "boolean" + case .any: return "any" + case .record(let value): return "Record" + case .enumeration(let values): return values.map { "\"\($0)\"" }.joined(separator: " | ") + case .literal(let value): + if case .string(let string) = value { return "\"\(string)\"" } + return value.jsString + case .object(let props): + let fields = props.map { prop in + "\(prop.name)\(prop.isOptional ? "?" : ""): \(typeAnnotation(prop.type, binding: prop.isBinding))" + } + return "{\(fields.joined(separator: ", "))}" + } +} + +// MARK: - JSON Schema (Zod 4 `toJSONSchema` output) + +func jsonSchema(_ type: PropType) -> OpenUIValue { + switch type { + case .string: return ["type": "string"] + case .number: return ["type": "number"] + case .boolean: return ["type": "boolean"] + case .any: return [:] + case .enumeration(let values): + return ["type": "string", "enum": .array(values.map { .string($0) })] + case .literal(let value): + return ["type": .string(value.jsTypeof), "const": value] + case .array(let inner): return ["type": "array", "items": jsonSchema(inner)] + case .object(let props): return objectSchema(props) + case .record(let value): + return [ + "type": "object", "propertyNames": ["type": "string"], + "additionalProperties": jsonSchema(value), + ] + case .component(let name): return ["$ref": .string("#/$defs/\(name)")] + case .union(let options): return ["anyOf": .array(options.map(jsonSchema))] + case .named(_, let inner): return jsonSchema(inner) + } +} + +private func propSchema(_ prop: Prop) -> OpenUIValue { + var schema = OpenUIObject() + if let defaultValue = prop.defaultValue { schema["default"] = defaultValue } + for (key, value) in jsonSchema(prop.type).objectValue ?? OpenUIObject() { schema[key] = value } + if let description = prop.description { schema["description"] = .string(description) } + return .object(schema) +} + +func objectSchema(_ props: [Prop]) -> OpenUIValue { + var schema: OpenUIObject = ["type": "object"] + schema["properties"] = .object(OpenUIObject(props.map { ($0.name, propSchema($0)) })) + let required = props.filter(\.isSchemaRequired).map { OpenUIValue.string($0.name) } + if !required.isEmpty { schema["required"] = .array(required) } + schema["additionalProperties"] = false + return .object(schema) +} + +// MARK: - Library + +/// A component library: the components a model may use, their prompt, and the +/// schema the parser maps positional arguments with. `Content` is how a UI +/// layer renders each component. +public struct Library: ComponentLibrary { + /// Components in library order (the order of the prompt and the schema). + public let components: [ComponentDefinition] + public let root: String? + public let componentGroups: [ComponentGroup]? + public let id: String? + public let paramMap: ParamMap + private let byName: [String: Int] + private let bindings: Set + + public init( + components: [ComponentDefinition], root: String? = nil, + componentGroups: [ComponentGroup]? = nil, id: String? = nil + ) { + let byName = Dictionary( + components.enumerated().map { ($0.element.name, $0.offset) }, uniquingKeysWith: { $1 }) + if let root, byName[root] == nil { + preconditionFailure( + "[createLibrary] Root component \"\(root)\" was not found in components. Available components: \(components.map(\.name).joined(separator: ", "))" + ) + } + self.components = components + self.root = root + self.componentGroups = componentGroups + self.id = id + self.byName = byName + self.bindings = Set( + components.flatMap { component in + component.schema.props.filter(\.isBinding).map { "\(component.name).\($0.name)" } + }) + self.paramMap = compileSchema(Self.buildSchema(components)) + } + + public var rootName: String? { root } + + public func component(named name: String) -> ComponentDefinition? { + byName[name].map { components[$0] } + } + + public func isReactiveProp(_ component: String, _ prop: String) -> Bool { + bindings.contains("\(component).\(prop)") + } + + /// The library JSON Schema, shaped like lang-core's `library.toJSONSchema()`. + public func toJSONSchema() -> OpenUIValue { + Self.buildSchema(components) + } + + private static func buildSchema(_ components: [ComponentDefinition]) -> OpenUIValue { + var defs = OpenUIObject() + var properties = OpenUIObject() + for component in components { + defs[component.name] = component.schema.jsonSchema + properties[component.name] = ["$ref": .string("#/$defs/\(component.name)")] + } + var root: OpenUIObject = ["$schema": "https://json-schema.org/draft/2020-12/schema"] + root["type"] = "object" + root["properties"] = .object(properties) + root["required"] = .array(components.map { .string($0.name) }) + root["additionalProperties"] = false + root["$defs"] = .object(defs) + return .object(root) + } + + /// The prompt inputs for this library. + public func promptSpec(_ options: PromptOptions = PromptOptions()) -> PromptSpec { + PromptSpec( + root: root, + components: components.map { + ( + $0.name, + ComponentPromptSpec(signature: $0.schema.signature, description: $0.schema.description) + ) + }, componentGroups: componentGroups, options: options) + } + + /// The system prompt for this library. + public func prompt(_ options: PromptOptions = PromptOptions()) -> String { + generatePrompt(promptSpec(options)) + } + + /// A JSON `LibrarySpec` (root, component signatures, groups, schema), the + /// same shape as lang-core's `library.toSpec()`. A server can pass it to + /// `generateSystemPrompt({ library })` to build the prompt for this app. + public func toSpec() -> OpenUIValue { + var spec = OpenUIObject() + spec["root"] = root.map { .string($0) } ?? .undefined + spec["components"] = .object( + OpenUIObject( + components.map { component in + var entry: OpenUIObject = ["signature": .string(component.schema.signature)] + entry["description"] = .string(component.schema.description) + return (component.name, .object(entry)) + })) + if let componentGroups { + spec["componentGroups"] = .array( + componentGroups.map { group in + var entry: OpenUIObject = ["name": .string(group.name)] + entry["components"] = .array(group.components.map { .string($0) }) + if let notes = group.notes { entry["notes"] = .array(notes.map { .string($0) }) } + return .object(entry) + }) + } + spec["schema"] = toJSONSchema() + if let id { spec["id"] = .string(id) } + return .object(spec) + } +} + +// Libraries are usually global constants; with sendable content (SwiftUI's +// main-actor render closures are) they can be shared across concurrency domains. +extension ComponentDefinition: Sendable where Content: Sendable {} +extension Library: Sendable where Content: Sendable {} diff --git a/packages/swift-lang/Sources/OpenUILang/Prompt.swift b/packages/swift-lang/Sources/OpenUILang/Prompt.swift new file mode 100644 index 0000000000..6dca0c76b0 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Prompt.swift @@ -0,0 +1,676 @@ +/// A tool the model can call through `Query()` / `Mutation()`. Shaped like an +/// MCP tool (name, description, input and output JSON Schemas). +public struct ToolSpec: Sendable, Equatable { + public var name: String + public var description: String? + public var inputSchema: OpenUIValue + public var outputSchema: OpenUIValue + + public init( + name: String, description: String? = nil, inputSchema: OpenUIValue = [:], + outputSchema: OpenUIValue = .undefined + ) { + self.name = name + self.description = description + self.inputSchema = inputSchema + self.outputSchema = outputSchema + } +} + +/// A tool listed in the prompt: a bare name or a full spec. +public enum ToolDescriptor: Sendable, Equatable { + case name(String) + case spec(ToolSpec) +} + +/// A component's prompt entry: its signature and description. +public struct ComponentPromptSpec: Sendable, Equatable { + public var signature: String + public var description: String? + + public init(signature: String, description: String? = nil) { + self.signature = signature + self.description = description + } +} + +/// A named group of components in the prompt, with optional notes. +public struct ComponentGroup: Sendable, Equatable { + public var name: String + public var components: [String] + public var notes: [String]? + + public init(name: String, components: [String], notes: [String]? = nil) { + self.name = name + self.components = components + self.notes = notes + } +} + +/// Options that shape the generated system prompt. +public struct PromptOptions: Sendable, Equatable { + public var preamble: String? + public var additionalRules: [String]? + public var examples: [String]? + public var toolExamples: [String]? + public var tools: [ToolDescriptor]? + public var editMode: Bool? + public var inlineMode: Bool? + /// Enables Query(), Mutation(), @Run. Defaults to true when tools are given. + public var toolCalls: Bool? + /// Enables $variables, @Set, @Reset. Defaults to `toolCalls`. + public var bindings: Bool? + + public init( + preamble: String? = nil, additionalRules: [String]? = nil, examples: [String]? = nil, + toolExamples: [String]? = nil, tools: [ToolDescriptor]? = nil, editMode: Bool? = nil, + inlineMode: Bool? = nil, toolCalls: Bool? = nil, bindings: Bool? = nil + ) { + self.preamble = preamble + self.additionalRules = additionalRules + self.examples = examples + self.toolExamples = toolExamples + self.tools = tools + self.editMode = editMode + self.inlineMode = inlineMode + self.toolCalls = toolCalls + self.bindings = bindings + } +} + +/// Everything prompt generation needs: the library's component signatures and the options. +public struct PromptSpec: Sendable, Equatable { + public var root: String? + /// Component entries in library order. + public var components: [(name: String, spec: ComponentPromptSpec)] + public var componentGroups: [ComponentGroup]? + public var options: PromptOptions + + public init( + root: String?, components: [(name: String, spec: ComponentPromptSpec)], + componentGroups: [ComponentGroup]? = nil, options: PromptOptions = PromptOptions() + ) { + self.root = root + self.components = components + self.componentGroups = componentGroups + self.options = options + } + + public static func == (lhs: PromptSpec, rhs: PromptSpec) -> Bool { + lhs.root == rhs.root && lhs.components.map(\.name) == rhs.components.map(\.name) + && lhs.components.map(\.spec) == rhs.components.map(\.spec) + && lhs.componentGroups == rhs.componentGroups && lhs.options == rhs.options + } +} + +// MARK: - JSON Schema helpers + +private func jsonSchemaTypeString(_ schema: OpenUIValue) -> String { + switch schema["type"].stringValue { + case "string": + if let values = schema["enum"].arrayValue { + return values.map { "\"\($0.jsString)\"" }.joined(separator: " | ") + } + return "string" + case "number", "integer": + return "number" + case "boolean": + return "boolean" + case "array": + if case .object = schema["items"] { return "\(jsonSchemaTypeString(schema["items"]))[]" } + return "any[]" + case "object": + if let props = schema["properties"].objectValue, !props.isEmpty { + let required = (schema["required"].arrayValue ?? []).compactMap(\.stringValue) + let fields = props.entries.map { key, value in + "\(key)\(required.contains(key) ? "" : "?"): \(jsonSchemaTypeString(value))" + } + return "{\(fields.joined(separator: ", "))}" + } + return "object" + default: + return "any" + } +} + +/// A placeholder value shaped like an output schema, for Query defaults hints. +private func defaultForSchema(_ schema: OpenUIValue) -> OpenUIValue { + switch schema["type"].stringValue { + case "string": return "" + case "number", "integer": return 0 + case "boolean": return false + case "array": return [] + case "object": + guard let props = schema["properties"].objectValue, !props.isEmpty else { return [:] } + return .object(OpenUIObject(props.entries.map { ($0.key, defaultForSchema($0.value)) })) + default: return .null + } +} + +// MARK: - Sections + +private let defaultPreamble = + "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang." + +private func syntaxRules(_ rootName: String, supportsExpressions: Bool, bindings: Bool) -> String { + var lines = [ + "## Syntax Rules", + "", + "1. Each statement is on its own line: `identifier = Expression`", + "2. `root` is the entry point — every program must define `root = \(rootName)(...)`", + "3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)", + "4. Use references for readability: define `name = ...` on one line, then use `name` later", + "5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.", + "6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks", + "7. Optional arguments can be omitted from the end", + ] + var ruleNumber = 8 + func rule(_ text: String) { + lines.append("\(ruleNumber). \(text)") + ruleNumber += 1 + } + if bindings { + rule( + "Declare mutable state with `$varName = defaultValue`. Components marked with `$binding` can read/write these. Undeclared $variables are auto-created with null default." + ) + } + if supportsExpressions { + rule("String concatenation: `\"text\" + $var + \"more\"`") + rule( + "Dot member access: `query.field` reads a field; on arrays it extracts that field from every element" + ) + rule("Index access: `arr[0]`, `data[index]`") + rule( + "Arithmetic operators: +, -, *, /, % (work on numbers; + is string concat when either side is a string)" + ) + rule("Comparison: ==, !=, >, <, >=, <=") + rule("Logical: &&, ||, ! (prefix)") + rule("Ternary: `condition ? valueIfTrue : valueIfFalse`") + rule("Parentheses for grouping: `(a + b) * c`") + } + lines.append("- Strings use double quotes with backslash escaping") + return lines.joined(separator: "\n") +} + +private func builtinFunctionsSection() -> String { + let builtinLines = builtinOrder.compactMap { builtins[$0] }.map { + "@\($0.signature) — \($0.description)" + } + let lazyLines = lazyBuiltinDefs.keys.sorted().map { + "@\(lazyBuiltinDefs[$0]!.signature) — \(lazyBuiltinDefs[$0]!.description)" + } + let lines = (builtinLines + lazyLines).joined(separator: "\n") + return """ + ## Built-in Functions + + Data functions prefixed with `@` to distinguish from components. These are the ONLY functions available — do NOT invent new ones. + Use @-prefixed built-in functions (@Count, @Sum, @Avg, @Min, @Max, @Round) on Query results — do NOT hardcode computed values. + + \(lines) + + Builtins compose — output of one is input to the next: + `@Count(@Filter(data.rows, "field", "==", "val"))` for KPIs/chart values, `@Round(@Avg(data.rows.score), 1)`, `@Each(data.rows, "item", Comp(item.field))` for per-item rendering. + Array pluck: `data.rows.field` extracts a field from every row → use with @Sum, @Avg, charts, tables. + + IMPORTANT @Each rule: The loop variable (e.g. "item") is ONLY available inside the @Each template expression. Always inline the template — do NOT extract it to a separate statement. + CORRECT: `Col("Actions", @Each(rows, "t", Button("Edit", Action([@Set($id, t.id)]))))` + WRONG: `myBtn = Button("Edit", Action([@Set($id, t.id)]))` then `Col("Actions", @Each(rows, "t", myBtn))` — t is undefined in myBtn. + """ +} + +private let querySection = """ + ## Query — Live Data Fetching + + Fetch data from available tools. Returns defaults instantly, swaps in real data when it arrives. + + ``` + metrics = Query("tool_name", {arg1: value, arg2: $binding}, {defaultField: 0, defaultData: []}, refreshInterval?) + ``` + + - First arg: tool name (string) + - Second arg: arguments object (may reference $bindings — re-fetches automatically on change) + - Third arg: default data (rendered immediately before fetch resolves) + - Fourth arg (optional): refresh interval in seconds (e.g. 30 for auto-refresh every 30s) + - Use dot access on results: metrics.totalEvents, metrics.data.day (array pluck) + - Query results must use regular identifiers: `metrics = Query(...)`, NOT `$metrics = Query(...)` + - Manual refresh: `Button("Refresh", Action([@Run(query1), @Run(query2)]), "secondary")` — re-fetches the listed queries + - Refresh all queries: create Action with @Run for each query + """ + +private let mutationSection = """ + ## Mutation — Write Operations + + Execute state-changing tool calls (create, update, delete). Unlike Query (auto-fetches on render), Mutation fires only on button click via Action. + + ``` + result = Mutation("tool_name", {arg1: $binding, arg2: "value"}) + ``` + + - First arg: tool name (string) + - Second arg: arguments object (evaluated with current $binding values at click time) + - result.status: "idle" | "loading" | "success" | "error" + - result.data: tool response on success + - result.error: error message on failure + - Mutation results use regular identifiers: `result = Mutation(...)`, NOT `$result` + - Show loading state: `result.status == "loading" ? TextContent("Saving...") : null` + """ + +private func actionSection(toolCalls: Bool, bindings: Bool) -> String { + var steps = [ + "- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")", + "- @OpenUrl(\"https://...\") — Navigate to a URL", + ] + if bindings { + steps.append("- @Set($variable, value) — Set a $variable to a specific value") + steps.append( + "- @Reset($var1, $var2, ...) — Reset $variables to their declared defaults (e.g. @Reset($title, $priority) restores $title=\"\" and $priority=\"medium\")" + ) + } + if toolCalls { + steps.insert( + "- @Run(queryOrMutationRef) — Execute a Mutation or re-fetch a Query (ref must be a declared Query/Mutation)", + at: 0) + } + + var examples: [String] = [] + if toolCalls { + examples.append( + """ + Example — mutation + refresh + reset (PREFERRED pattern): + ``` + $binding = "default" + result = Mutation("tool_name", {field: $binding}) + data = Query("tool_name", {}, {rows: []}) + onSubmit = Action([@Run(result), @Run(data), @Reset($binding)]) + ``` + """) + } + examples.append( + """ + Example — simple nav: + ``` + viewBtn = Button("View", Action([@OpenUrl("https://example.com")])) + ``` + """) + + var rules = [ + "- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work" + ] + if toolCalls { + rules.append("- If a @Run(mutation) step fails, remaining steps are skipped (halt on failure)") + rules.append("- @Run(queryRef) re-fetches the query (fire-and-forget, cannot fail)") + } + + return """ + ## Action — Button Behavior + + Action([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order. + Buttons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])). + + Available steps: + \(steps.joined(separator: "\n")) + + \(examples.joined(separator: "\n\n")) + + \(rules.joined(separator: "\n")) + """ +} + +private let interactiveFiltersSection = """ + ## Interactive Filters + + To let the user filter data with a dropdown: + 1. Declare a $variable with a default: `$dateRange = "14"` + 2. Create a Select with name, items, and binding: `Select("dateRange", [SelectItem("7", "Last 7 days"), ...], null, null, $dateRange)` + 3. Wrap in FormControl for a label: `FormControl("Date Range", Select(...))` + 4. Pass $dateRange in Query args: `Query("tool", {dateRange: $dateRange}, {defaults})` + 5. When the user changes the Select, $dateRange updates and the Query automatically re-fetches + + FILTER WIRING RULE: If a $binding filter is visible in the UI, EVERY relevant Query MUST reference that $binding in its args. Never show a filter dropdown while hardcoding the query args. + + Rules for $variables: + - $variables hold simple values (strings or numbers), NOT arrays or objects + - $variables must be bound to a Select/Input component via the value argument (last positional arg) to be interactive + - Queries must use regular identifiers (NOT $variables): `metrics = Query(...)` not `$metrics = Query(...)` + - **Auto-declare**: You do NOT need to explicitly declare $variables. If you use `$foo` without declaring it, the parser auto-creates `$foo = null`. You can still declare explicitly to set a default: `$days = "14"` + + ## Forms + + Simple form — no $bindings needed. Field values are managed internally by the Form via the name prop: + ``` + contactForm = Form("contact", submitBtn, [nameField, emailField]) + nameField = FormControl("Name", Input("name", "Your name", "text", {required: true})) + emailField = FormControl("Email", Input("email", "your@email.com", "email", {required: true, email: true})) + submitBtn = Button("Submit") + ``` + + Use $bindings when you need to read field values elsewhere (in Action context, Query args, or conditionals). They are auto-declared: + ``` + $role = "engineer" + contactForm = Form("contact", submitBtn, [nameField, emailField, roleField]) + nameField = FormControl("Name", Input("name", "Enter your name", "text", {required: true}, $name)) + emailField = FormControl("Email", Input("email", "Enter your email", "email", {required: true, email: true}, $email)) + roleField = FormControl("Role", Select("role", [SelectItem("engineer", "Engineer"), SelectItem("designer", "Designer"), SelectItem("pm", "PM")], null, {required: true}, $role)) + submitBtn = Button("Submit") + ``` + + For form + mutation patterns (create, refresh, reset), see the Action section example above. + + IMPORTANT: Always add validation rules to form fields used with Mutations. Use OBJECT syntax: {required: true, email: true, minLength: 8}. The renderer shows error messages automatically and blocks submit when validation fails. + """ + +private let editModeSection = """ + ## Edit Mode + + The runtime merges by statement name: same name = replace, new name = append. + Output ONLY statements that changed or are new. Everything else is kept automatically. + + ### Delete + To remove a component, re-declare its parent without that component in the parent's children array. The removed component and any statements only it referenced are automatically garbage-collected. + + ### Patch size guide + - Changing a title or label: 1 statement + - Adding a component: 2-3 statements (the new component + parent update) + - Removing a component: 1 statement (re-declare parent without the removed child) + - Adding a filter + wiring to query: 3-5 statements + - Restructuring into tabs: 5-10 statements + + ### Rules + - Reuse existing statement names exactly — do not rename + - Do NOT re-emit unchanged statements — the runtime keeps them + - A typical edit patch is 1-10 statements, not 20+ + - If the existing code already satisfies the request, output only the root statement + - NEVER output the entire program as a patch. Only output what actually changes + - If you are about to output more than 10 statements, reconsider — most edits need fewer + """ + +private func streamingRules(_ rootName: String, supportsExpressions: Bool) -> String { + var steps = ["1. `root = \(rootName)(...)` — UI shell appears immediately"] + if supportsExpressions { + steps.append("2. $variable declarations — state ready for bindings") + steps.append( + "3. Query statements — defaults resolve immediately so components render with data") + steps.append("4. Component definitions — fill in with data already available") + steps.append("5. Data values — leaf content last") + } else { + steps.append("2. Component definitions — fill in as they stream") + steps.append("3. Data values — leaf content last") + } + return """ + ## Hoisting & Streaming (CRITICAL) + + openui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed. + + During streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in. + + **Recommended statement order for optimal streaming:** + \(steps.joined(separator: "\n")) + + Always write the root = \(rootName)(...) statement first so the UI shell appears immediately, even before child data has streamed in. + """ +} + +private let inlineModeSection = """ + ## Inline Mode + + You are in inline mode. You can respond in two ways: + + ### 1. Code response (when the user wants to CREATE or CHANGE the UI) + Wrap openui-lang code in triple-backtick fences. You can include explanatory text before/after: + + Here's your dashboard: + + ```openui-lang + root = RootComp([header, content]) + header = SomeHeader("Title") + content = SomeContent("Hello world") + ``` + + I created a simple layout with a header. + + ### 2. Text-only response (when the user asks a QUESTION) + If the user asks "what is this?", "explain the chart", "how does this work", etc. — respond with plain text. Do NOT output any openui-lang code. The existing dashboard stays unchanged. + + ### Rules + - When the user asks for changes, output ONLY the changed/new statements in a fenced block + - When the user asks a question, respond with text only — NO code. The dashboard stays unchanged. + - The parser extracts code from fences automatically. Text outside fences is shown as chat. + """ + +private let toolWorkflowSection = """ + ## Data Workflow + + When tools are available, follow this workflow: + 1. FIRST: Call the most relevant tool to inspect the real data shape before generating code + 2. Use Query() for READ operations (data that should stay live) — NEVER hardcode tool results as literal arrays or objects + 3. Use Mutation() for WRITE operations (create, update, delete) — triggered by button clicks via Action([@Run(mutationRef)]) + 4. Use the real data from step 1 as condensed Query defaults (3-5 rows) so the UI renders immediately + 5. Use @-prefixed builtins (@Count, @Filter, @Sort, @Sum) on Query results for KPIs and aggregations — the runtime evaluates these live on every refresh + 6. Hardcoded arrays are ONLY for static display data (labels, options) where no tool exists + + WRONG — you called a tool and got data back, but you inlined the results: + ``` + openCount = 2 + item1 = SomeComp("first item title") + item2 = SomeComp("second item title") + list = SomeList([item1, item2]) + chart = SomeChart(["A", "B"], [12, 8]) + ``` + This is static — it shows stale data and won't update. Creating item1, item2, item3... manually is ALWAYS wrong when a tool exists. + + RIGHT — use Query() for live data, Mutation() for writes, @builtins to derive values: + ``` + data = Query("tool_name", {}, {rows: []}) + openCount = @Count(@Filter(data.rows, "field", "==", "value")) + list = @Each(data.rows, "item", SomeComp(item.title, item.field)) + createResult = Mutation("create_tool", {title: $title}) + submitBtn = Button("Create", Action([@Run(createResult), @Run(data), @Reset($title)])) + ``` + Everything derives from the Query — when data refreshes, the entire dashboard updates automatically. + """ + +private func importantRules(_ rootName: String, toolCalls: Bool, bindings: Bool) -> String { + var verify = [ + "1. root = \(rootName)(...) is the FIRST line (for optimal streaming).", + "2. Every referenced name is defined. Every defined name (other than root) is reachable from root.", + ] + if toolCalls { verify.append("3. Every Query result is referenced by at least one component.") } + if bindings { + verify.append( + "\(toolCalls ? "4" : "3"). Every $binding appears in at least one component or expression.") + } + if toolCalls && bindings { + verify.append("5. Every visible filter $binding appears in at least one Query args object.") + } + return """ + ## Important Rules + - Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.) + + ## Final Verification + Before finishing, walk your output and verify: + \(verify.joined(separator: "\n")) + """ +} + +// MARK: - Tools + +private func renderToolSignature(_ tool: ToolSpec) -> String { + var args = "" + if let props = tool.inputSchema["properties"].objectValue, !props.isEmpty { + let required = (tool.inputSchema["required"].arrayValue ?? []).compactMap(\.stringValue) + args = props.entries.map { key, value in + "\(key)\(required.contains(key) ? "" : "?"): \(jsonSchemaTypeString(value))" + }.joined(separator: ", ") + } + let returnType = tool.outputSchema.isTruthy ? " → \(jsonSchemaTypeString(tool.outputSchema))" : "" + var line = "- \(tool.name)(\(args))\(returnType)" + if let description = tool.description, !description.isEmpty { line += "\n \(description)" } + return line +} + +private func renderToolsSection(_ tools: [ToolDescriptor]) -> String { + var lines = [ + "## Available Tools", + "", + "Use these with Query() for read operations or Mutation() for write operations. The LLM decides which is appropriate based on the tool's purpose.", + "", + ] + var specTools: [ToolSpec] = [] + for tool in tools { + if case .name(let name) = tool { lines.append("- \(name)") } + if case .spec(let spec) = tool { specTools.append(spec) } + } + for tool in specTools { lines.append(renderToolSignature(tool)) } + + let withOutput = specTools.filter { $0.outputSchema.isTruthy } + if !withOutput.isEmpty { + lines.append("") + lines.append("### Default values for Query results") + lines.append("") + lines.append("Use these shapes as minimal Query defaults:") + for tool in withOutput { + lines.append("- \(tool.name): `\(JSON.stringify(defaultForSchema(tool.outputSchema)))`") + } + } + lines.append("") + lines.append( + "CRITICAL: Use ONLY the tools listed above in Query() and Mutation() calls. Do NOT invent or guess tool names. If the user asks for functionality that doesn't match any available tool, use realistic mock data instead of fabricating a tool call." + ) + return lines.joined(separator: "\n") +} + +// MARK: - Component signatures + +private func componentSignatures( + _ spec: PromptSpec, toolCalls: Bool, bindings: Bool, usesActionExpression: Bool +) -> String { + var lines = [ + "## Component Signatures", + "", + "Arguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.", + ] + if usesActionExpression { + let steps = [ + toolCalls ? "@Run" : "", "@ToAssistant", "@OpenUrl", bindings ? "@Set" : "", + bindings ? "@Reset" : "", + ].filter { !$0.isEmpty } + lines.append( + "Props typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (\(steps.joined(separator: ", ")))." + ) + } + if bindings || spec.components.contains(where: { $0.spec.signature.contains("$binding") }) { + lines.append( + "Props marked `$binding` accept a `$variable` reference for two-way binding.") + } + + func format(_ component: ComponentPromptSpec) -> String { + if let description = component.description, !description.isEmpty { + return "\(component.signature) — \(description)" + } + return component.signature + } + let byName = Dictionary(spec.components.map { ($0.name, $0.spec) }, uniquingKeysWith: { $1 }) + + if let groups = spec.componentGroups, !groups.isEmpty { + var grouped: Set = [] + for group in groups { + lines.append("") + lines.append("### \(group.name)") + for name in group.components where !grouped.contains(name) { + guard let component = byName[name] else { continue } + grouped.insert(name) + lines.append(format(component)) + } + for note in group.notes ?? [] { lines.append(note) } + } + let ungrouped = spec.components.filter { !grouped.contains($0.name) } + if !ungrouped.isEmpty { + lines.append("") + lines.append("### Other") + for component in ungrouped { lines.append(format(component.spec)) } + } + } else { + lines.append("") + for component in spec.components { lines.append(format(component.spec)) } + } + return lines.joined(separator: "\n") +} + +// MARK: - Assembly + +/// Generates the system prompt that teaches a model OpenUI Lang and the +/// library's components. Matches lang-core's `generatePrompt`. +public func generatePrompt(_ spec: PromptSpec) -> String { + let rootName = spec.root ?? "Root" + let options = spec.options + let hasTools = !(options.tools ?? []).isEmpty + let toolCalls = options.toolCalls ?? hasTools + let bindings = options.bindings ?? toolCalls + let supportsExpressions = toolCalls || bindings + let usesActionExpression = spec.components.contains { + $0.spec.signature.contains("ActionExpression") + } + + var parts: [String] = [] + parts.append(options.preamble ?? defaultPreamble) + parts.append("") + parts.append(syntaxRules(rootName, supportsExpressions: supportsExpressions, bindings: bindings)) + parts.append("") + parts.append( + componentSignatures( + spec, toolCalls: toolCalls, bindings: bindings, usesActionExpression: usesActionExpression)) + + if supportsExpressions { + parts.append("") + parts.append(builtinFunctionsSection()) + } + if toolCalls { + parts.append("") + parts.append(querySection) + parts.append("") + parts.append(mutationSection) + } + if usesActionExpression { + parts.append("") + parts.append(actionSection(toolCalls: toolCalls, bindings: bindings)) + } + if toolCalls && bindings { + parts.append("") + parts.append(interactiveFiltersSection) + } + if toolCalls { + parts.append("") + parts.append(toolWorkflowSection) + } + if let tools = options.tools, !tools.isEmpty { + parts.append("") + parts.append(renderToolsSection(tools)) + } + parts.append("") + parts.append(streamingRules(rootName, supportsExpressions: supportsExpressions)) + + let examples = (options.examples ?? []) + (options.toolExamples ?? []) + if !examples.isEmpty { + parts.append("") + parts.append("## Examples") + parts.append("") + for example in examples { + parts.append(example) + parts.append("") + } + } + if options.editMode == true { + parts.append("") + parts.append(editModeSection) + } + if options.inlineMode == true { + parts.append("") + parts.append(inlineModeSection) + } + parts.append(importantRules(rootName, toolCalls: toolCalls, bindings: bindings)) + if let rules = options.additionalRules, !rules.isEmpty { + parts.append("") + for rule in rules { parts.append("- \(rule)") } + } + return parts.joined(separator: "\n") +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/chat-spec.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/chat-spec.json new file mode 100644 index 0000000000..4117eccb92 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/chat-spec.json @@ -0,0 +1,538 @@ +{ + "root": "Card", + "components": { + "Card": { + "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", + "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." + }, + "CardHeader": { + "signature": "CardHeader(title?: string, subtitle?: string)", + "description": "Header with optional title and subtitle" + }, + "TextContent": { + "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "MarkDownRenderer": { + "signature": "MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")", + "description": "Renders markdown text with optional container variant" + }, + "Callout": { + "signature": "Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)", + "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." + }, + "TextCallout": { + "signature": "TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)", + "description": "Text callout with variant, title, and description" + }, + "Image": { + "signature": "Image(alt: string, src?: string)", + "description": "Image with alt text and optional URL" + }, + "ImageBlock": { + "signature": "ImageBlock(src: string, alt?: string)", + "description": "Image block with loading state" + }, + "ImageGallery": { + "signature": "ImageGallery(images: {src: string, alt?: string, details?: string}[])", + "description": "Gallery grid of images with modal preview" + }, + "CodeBlock": { + "signature": "CodeBlock(language: string, codeString: string)", + "description": "Syntax-highlighted code block" + }, + "Separator": { + "signature": "Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)", + "description": "Visual divider between content sections" + }, + "Table": { + "signature": "Table(columns: Col[])", + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", + "description": "Column definition — holds label + data array" + }, + "BarChart": { + "signature": "BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Vertical bars; use for comparing values across categories with one or more series" + }, + "LineChart": { + "signature": "LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Lines over categories; use for trends and continuous data over time" + }, + "AreaChart": { + "signature": "AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Filled area under lines; use for cumulative totals or volume trends over time" + }, + "RadarChart": { + "signature": "RadarChart(labels: string[], series: Series[])", + "description": "Spider/web chart; use for comparing multiple variables across one or more entities" + }, + "HorizontalBarChart": { + "signature": "HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)", + "description": "Horizontal bars; prefer when category labels are long or for ranked lists" + }, + "Series": { + "signature": "Series(category: string, values: number[])", + "description": "One data series" + }, + "PieChart": { + "signature": "PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")", + "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" + }, + "RadialChart": { + "signature": "RadialChart(labels: string[], values: number[])", + "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" + }, + "SingleStackedBarChart": { + "signature": "SingleStackedBarChart(labels: string[], values: number[])", + "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" + }, + "Slice": { + "signature": "Slice(category: string, value: number)", + "description": "One slice with label and numeric value" + }, + "ScatterChart": { + "signature": "ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)", + "description": "X/Y scatter plot; use for correlations, distributions, and clustering" + }, + "ScatterSeries": { + "signature": "ScatterSeries(name: string, points: Point[])", + "description": "Named dataset" + }, + "Point": { + "signature": "Point(x: number, y: number, z?: number)", + "description": "Data point with numeric coordinates" + }, + "Form": { + "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", + "description": "Form container with fields and explicit action buttons" + }, + "FormControl": { + "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", + "description": "Field with label, input component, and optional hint text" + }, + "Label": { + "signature": "Label(text: string)", + "description": "Text label" + }, + "Input": { + "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "TextArea": { + "signature": "TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Select": { + "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", + "description": "" + }, + "SelectItem": { + "signature": "SelectItem(value: string, label: string)", + "description": "Option for Select" + }, + "DatePicker": { + "signature": "DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Slider": { + "signature": "Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "Numeric slider input; supports continuous and discrete (stepped) variants" + }, + "CheckBoxGroup": { + "signature": "CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)", + "description": "" + }, + "CheckBoxItem": { + "signature": "CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)", + "description": "" + }, + "RadioGroup": { + "signature": "RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "RadioItem": { + "signature": "RadioItem(label: string, description: string, value: string)", + "description": "" + }, + "SwitchGroup": { + "signature": "SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)", + "description": "Group of switch toggles" + }, + "SwitchItem": { + "signature": "SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)", + "description": "Individual switch toggle" + }, + "Button": { + "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", + "description": "Clickable button" + }, + "Buttons": { + "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "ListBlock": { + "signature": "ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")", + "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." + }, + "ListItem": { + "signature": "ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)", + "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." + }, + "FollowUpBlock": { + "signature": "FollowUpBlock(items: FollowUpItem[])", + "description": "List of clickable follow-up suggestions placed at the end of a response" + }, + "FollowUpItem": { + "signature": "FollowUpItem(text: string)", + "description": "Clickable follow-up suggestion — when clicked, sends text as user message" + }, + "SectionBlock": { + "signature": "SectionBlock(sections: SectionItem[], isFoldable?: boolean)", + "description": "Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section." + }, + "SectionItem": { + "signature": "SectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[])", + "description": "Section with a label and collapsible content — used inside SectionBlock" + }, + "Tabs": { + "signature": "Tabs(items: TabItem[])", + "description": "Tabbed container" + }, + "TabItem": { + "signature": "TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[])", + "description": "value is unique id, trigger is tab label, content is array of components" + }, + "Accordion": { + "signature": "Accordion(items: AccordionItem[])", + "description": "Collapsible sections" + }, + "AccordionItem": { + "signature": "AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[])", + "description": "value is unique id, trigger is section title" + }, + "Steps": { + "signature": "Steps(items: StepsItem[])", + "description": "Step-by-step guide" + }, + "StepsItem": { + "signature": "StepsItem(title: string, details: string)", + "description": "title and details text for one step" + }, + "Carousel": { + "signature": "Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\")", + "description": "Horizontal scrollable carousel" + }, + "TagBlock": { + "signature": "TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")", + "description": "tags is an array of strings; optional size sm | md | lg" + }, + "Tag": { + "signature": "Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")", + "description": "Styled tag/badge with optional Icon and variant" + }, + "EntityList": { + "signature": "EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})", + "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." + }, + "InlineHeader": { + "signature": "InlineHeader(heading: string, description?: string)", + "description": "Compact section heading with an optional one-line description, for use inside cards." + }, + "Icon": { + "signature": "Icon(name: string, category?: string)", + "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." + }, + "IconButton": { + "signature": "IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")", + "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." + }, + "EditableTable": { + "signature": "EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])", + "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" + }, + "ChipItem": { + "signature": "ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)", + "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." + }, + "Chips": { + "signature": "Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", + "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." + }, + "OptionCard": { + "signature": "OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)", + "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." + }, + "OptionCards": { + "signature": "OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", + "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." + }, + "Text": { + "signature": "Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", + "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "BoldText": { + "signature": "BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", + "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "IconText": { + "signature": "IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")", + "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." + }, + "ImageText": { + "signature": "ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)", + "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." + }, + "ImageTextLarge": { + "signature": "ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)", + "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." + }, + "MetricIndicatorInline": { + "signature": "MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})", + "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." + }, + "MetricIndicatorWithStrikethrough": { + "signature": "MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})", + "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." + }, + "SnippetCardItem": { + "signature": "SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)", + "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." + }, + "SnippetCardBlock": { + "signature": "SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." + }, + "OverviewCardItem": { + "signature": "OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)", + "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." + }, + "OverviewCardBlock": { + "signature": "OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." + }, + "ContextCardItem": { + "signature": "ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)", + "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." + }, + "ContextCardBlock": { + "signature": "ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." + }, + "CompositeCardItem": { + "signature": "CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})", + "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." + }, + "CompositeCardBlock": { + "signature": "CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." + }, + "VisualCardItem": { + "signature": "VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)", + "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." + }, + "VisualCardBlock": { + "signature": "VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." + } + }, + "componentGroups": [ + { + "name": "Content", + "components": [ + "CardHeader", + "TextContent", + "MarkDownRenderer", + "Callout", + "TextCallout", + "Image", + "ImageBlock", + "ImageGallery", + "CodeBlock", + "Separator", + "InlineHeader" + ], + "notes": [ + "- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).", + "- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card." + ] + }, + { + "name": "Tables", + "components": [ + "Table", + "Col", + "EditableTable" + ], + "notes": [ + "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", + "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes." + ] + }, + { + "name": "Charts (2D)", + "components": [ + "BarChart", + "LineChart", + "AreaChart", + "RadarChart", + "HorizontalBarChart", + "Series" + ] + }, + { + "name": "Charts (1D)", + "components": [ + "PieChart", + "RadialChart", + "SingleStackedBarChart", + "Slice" + ] + }, + { + "name": "Charts (Scatter)", + "components": [ + "ScatterChart", + "ScatterSeries", + "Point" + ] + }, + { + "name": "Forms", + "components": [ + "Form", + "FormControl", + "Label", + "Input", + "TextArea", + "Select", + "SelectItem", + "DatePicker", + "Slider", + "CheckBoxGroup", + "CheckBoxItem", + "RadioGroup", + "RadioItem", + "SwitchGroup", + "SwitchItem", + "Chips", + "ChipItem", + "OptionCards", + "OptionCard" + ], + "notes": [ + "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", + "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", + "- Define EACH FormControl as its own reference — do NOT inline all controls in one array.", + "- NEVER nest Form inside Form.", + "- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).", + "- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }", + "- The renderer shows error messages automatically — do NOT generate error text in the UI" + ] + }, + { + "name": "Buttons", + "components": [ + "Button", + "Buttons", + "Icon", + "IconButton" + ], + "notes": [ + "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard." + ] + }, + { + "name": "Lists & Follow-ups", + "components": [ + "ListBlock", + "ListItem", + "FollowUpBlock", + "FollowUpItem" + ], + "notes": [ + "- Use ListBlock with ListItem references for numbered lists.", + "- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.", + "- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.", + "- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.", + "- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })" + ] + }, + { + "name": "Sections", + "components": [ + "SectionBlock", + "SectionItem" + ], + "notes": [ + "- SectionBlock renders collapsible accordion sections that auto-open as they stream.", + "- Each section needs a unique `value` id, a `trigger` label, and a `content` array.", + "- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])", + "- Set isFoldable=false to render sections as flat headers instead of accordion." + ] + }, + { + "name": "Layout", + "components": [ + "Tabs", + "TabItem", + "Accordion", + "AccordionItem", + "Steps", + "StepsItem", + "Carousel" + ], + "notes": [ + "- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.", + "- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])", + "- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.", + "- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.", + "- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs." + ] + }, + { + "name": "Data Display", + "components": [ + "TagBlock", + "Tag", + "EntityList" + ], + "notes": [ + "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not." + ] + }, + { + "name": "Cards", + "components": [ + "SnippetCardBlock", + "SnippetCardItem", + "OverviewCardBlock", + "OverviewCardItem", + "ContextCardBlock", + "ContextCardItem", + "CompositeCardBlock", + "CompositeCardItem", + "VisualCardBlock", + "VisualCardItem", + "Text", + "BoldText", + "IconText", + "ImageText", + "ImageTextLarge", + "MetricIndicatorInline", + "MetricIndicatorWithStrikethrough" + ], + "notes": [ + "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", + "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", + "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", + "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", + "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", + "- VisualCardItem: image-first card with a BoldText body and optional Tag.", + "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card." + ] + } + ] +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/prompts.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/prompts.json new file mode 100644 index 0000000000..4ab4862d19 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/prompts.json @@ -0,0 +1,1634 @@ +[ + { + "name": "chat-default", + "spec": { + "root": "Card", + "components": { + "Card": { + "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", + "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." + }, + "CardHeader": { + "signature": "CardHeader(title?: string, subtitle?: string)", + "description": "Header with optional title and subtitle" + }, + "TextContent": { + "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "MarkDownRenderer": { + "signature": "MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")", + "description": "Renders markdown text with optional container variant" + }, + "Callout": { + "signature": "Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)", + "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." + }, + "TextCallout": { + "signature": "TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)", + "description": "Text callout with variant, title, and description" + }, + "Image": { + "signature": "Image(alt: string, src?: string)", + "description": "Image with alt text and optional URL" + }, + "ImageBlock": { + "signature": "ImageBlock(src: string, alt?: string)", + "description": "Image block with loading state" + }, + "ImageGallery": { + "signature": "ImageGallery(images: {src: string, alt?: string, details?: string}[])", + "description": "Gallery grid of images with modal preview" + }, + "CodeBlock": { + "signature": "CodeBlock(language: string, codeString: string)", + "description": "Syntax-highlighted code block" + }, + "Separator": { + "signature": "Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)", + "description": "Visual divider between content sections" + }, + "Table": { + "signature": "Table(columns: Col[])", + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", + "description": "Column definition — holds label + data array" + }, + "BarChart": { + "signature": "BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Vertical bars; use for comparing values across categories with one or more series" + }, + "LineChart": { + "signature": "LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Lines over categories; use for trends and continuous data over time" + }, + "AreaChart": { + "signature": "AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Filled area under lines; use for cumulative totals or volume trends over time" + }, + "RadarChart": { + "signature": "RadarChart(labels: string[], series: Series[])", + "description": "Spider/web chart; use for comparing multiple variables across one or more entities" + }, + "HorizontalBarChart": { + "signature": "HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)", + "description": "Horizontal bars; prefer when category labels are long or for ranked lists" + }, + "Series": { + "signature": "Series(category: string, values: number[])", + "description": "One data series" + }, + "PieChart": { + "signature": "PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")", + "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" + }, + "RadialChart": { + "signature": "RadialChart(labels: string[], values: number[])", + "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" + }, + "SingleStackedBarChart": { + "signature": "SingleStackedBarChart(labels: string[], values: number[])", + "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" + }, + "Slice": { + "signature": "Slice(category: string, value: number)", + "description": "One slice with label and numeric value" + }, + "ScatterChart": { + "signature": "ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)", + "description": "X/Y scatter plot; use for correlations, distributions, and clustering" + }, + "ScatterSeries": { + "signature": "ScatterSeries(name: string, points: Point[])", + "description": "Named dataset" + }, + "Point": { + "signature": "Point(x: number, y: number, z?: number)", + "description": "Data point with numeric coordinates" + }, + "Form": { + "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", + "description": "Form container with fields and explicit action buttons" + }, + "FormControl": { + "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", + "description": "Field with label, input component, and optional hint text" + }, + "Label": { + "signature": "Label(text: string)", + "description": "Text label" + }, + "Input": { + "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "TextArea": { + "signature": "TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Select": { + "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", + "description": "" + }, + "SelectItem": { + "signature": "SelectItem(value: string, label: string)", + "description": "Option for Select" + }, + "DatePicker": { + "signature": "DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Slider": { + "signature": "Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "Numeric slider input; supports continuous and discrete (stepped) variants" + }, + "CheckBoxGroup": { + "signature": "CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)", + "description": "" + }, + "CheckBoxItem": { + "signature": "CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)", + "description": "" + }, + "RadioGroup": { + "signature": "RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "RadioItem": { + "signature": "RadioItem(label: string, description: string, value: string)", + "description": "" + }, + "SwitchGroup": { + "signature": "SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)", + "description": "Group of switch toggles" + }, + "SwitchItem": { + "signature": "SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)", + "description": "Individual switch toggle" + }, + "Button": { + "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", + "description": "Clickable button" + }, + "Buttons": { + "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "ListBlock": { + "signature": "ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")", + "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." + }, + "ListItem": { + "signature": "ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)", + "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." + }, + "FollowUpBlock": { + "signature": "FollowUpBlock(items: FollowUpItem[])", + "description": "List of clickable follow-up suggestions placed at the end of a response" + }, + "FollowUpItem": { + "signature": "FollowUpItem(text: string)", + "description": "Clickable follow-up suggestion — when clicked, sends text as user message" + }, + "SectionBlock": { + "signature": "SectionBlock(sections: SectionItem[], isFoldable?: boolean)", + "description": "Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section." + }, + "SectionItem": { + "signature": "SectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[])", + "description": "Section with a label and collapsible content — used inside SectionBlock" + }, + "Tabs": { + "signature": "Tabs(items: TabItem[])", + "description": "Tabbed container" + }, + "TabItem": { + "signature": "TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[])", + "description": "value is unique id, trigger is tab label, content is array of components" + }, + "Accordion": { + "signature": "Accordion(items: AccordionItem[])", + "description": "Collapsible sections" + }, + "AccordionItem": { + "signature": "AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[])", + "description": "value is unique id, trigger is section title" + }, + "Steps": { + "signature": "Steps(items: StepsItem[])", + "description": "Step-by-step guide" + }, + "StepsItem": { + "signature": "StepsItem(title: string, details: string)", + "description": "title and details text for one step" + }, + "Carousel": { + "signature": "Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\")", + "description": "Horizontal scrollable carousel" + }, + "TagBlock": { + "signature": "TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")", + "description": "tags is an array of strings; optional size sm | md | lg" + }, + "Tag": { + "signature": "Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")", + "description": "Styled tag/badge with optional Icon and variant" + }, + "EntityList": { + "signature": "EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})", + "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." + }, + "InlineHeader": { + "signature": "InlineHeader(heading: string, description?: string)", + "description": "Compact section heading with an optional one-line description, for use inside cards." + }, + "Icon": { + "signature": "Icon(name: string, category?: string)", + "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." + }, + "IconButton": { + "signature": "IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")", + "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." + }, + "EditableTable": { + "signature": "EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])", + "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" + }, + "ChipItem": { + "signature": "ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)", + "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." + }, + "Chips": { + "signature": "Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", + "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." + }, + "OptionCard": { + "signature": "OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)", + "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." + }, + "OptionCards": { + "signature": "OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", + "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." + }, + "Text": { + "signature": "Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", + "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "BoldText": { + "signature": "BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", + "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "IconText": { + "signature": "IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")", + "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." + }, + "ImageText": { + "signature": "ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)", + "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." + }, + "ImageTextLarge": { + "signature": "ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)", + "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." + }, + "MetricIndicatorInline": { + "signature": "MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})", + "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." + }, + "MetricIndicatorWithStrikethrough": { + "signature": "MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})", + "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." + }, + "SnippetCardItem": { + "signature": "SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)", + "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." + }, + "SnippetCardBlock": { + "signature": "SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." + }, + "OverviewCardItem": { + "signature": "OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)", + "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." + }, + "OverviewCardBlock": { + "signature": "OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." + }, + "ContextCardItem": { + "signature": "ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)", + "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." + }, + "ContextCardBlock": { + "signature": "ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." + }, + "CompositeCardItem": { + "signature": "CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})", + "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." + }, + "CompositeCardBlock": { + "signature": "CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." + }, + "VisualCardItem": { + "signature": "VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)", + "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." + }, + "VisualCardBlock": { + "signature": "VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." + } + }, + "componentGroups": [ + { + "name": "Content", + "components": [ + "CardHeader", + "TextContent", + "MarkDownRenderer", + "Callout", + "TextCallout", + "Image", + "ImageBlock", + "ImageGallery", + "CodeBlock", + "Separator", + "InlineHeader" + ], + "notes": [ + "- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).", + "- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card." + ] + }, + { + "name": "Tables", + "components": [ + "Table", + "Col", + "EditableTable" + ], + "notes": [ + "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", + "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes." + ] + }, + { + "name": "Charts (2D)", + "components": [ + "BarChart", + "LineChart", + "AreaChart", + "RadarChart", + "HorizontalBarChart", + "Series" + ] + }, + { + "name": "Charts (1D)", + "components": [ + "PieChart", + "RadialChart", + "SingleStackedBarChart", + "Slice" + ] + }, + { + "name": "Charts (Scatter)", + "components": [ + "ScatterChart", + "ScatterSeries", + "Point" + ] + }, + { + "name": "Forms", + "components": [ + "Form", + "FormControl", + "Label", + "Input", + "TextArea", + "Select", + "SelectItem", + "DatePicker", + "Slider", + "CheckBoxGroup", + "CheckBoxItem", + "RadioGroup", + "RadioItem", + "SwitchGroup", + "SwitchItem", + "Chips", + "ChipItem", + "OptionCards", + "OptionCard" + ], + "notes": [ + "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", + "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", + "- Define EACH FormControl as its own reference — do NOT inline all controls in one array.", + "- NEVER nest Form inside Form.", + "- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).", + "- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }", + "- The renderer shows error messages automatically — do NOT generate error text in the UI" + ] + }, + { + "name": "Buttons", + "components": [ + "Button", + "Buttons", + "Icon", + "IconButton" + ], + "notes": [ + "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard." + ] + }, + { + "name": "Lists & Follow-ups", + "components": [ + "ListBlock", + "ListItem", + "FollowUpBlock", + "FollowUpItem" + ], + "notes": [ + "- Use ListBlock with ListItem references for numbered lists.", + "- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.", + "- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.", + "- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.", + "- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })" + ] + }, + { + "name": "Sections", + "components": [ + "SectionBlock", + "SectionItem" + ], + "notes": [ + "- SectionBlock renders collapsible accordion sections that auto-open as they stream.", + "- Each section needs a unique `value` id, a `trigger` label, and a `content` array.", + "- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])", + "- Set isFoldable=false to render sections as flat headers instead of accordion." + ] + }, + { + "name": "Layout", + "components": [ + "Tabs", + "TabItem", + "Accordion", + "AccordionItem", + "Steps", + "StepsItem", + "Carousel" + ], + "notes": [ + "- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.", + "- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])", + "- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.", + "- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.", + "- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs." + ] + }, + { + "name": "Data Display", + "components": [ + "TagBlock", + "Tag", + "EntityList" + ], + "notes": [ + "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not." + ] + }, + { + "name": "Cards", + "components": [ + "SnippetCardBlock", + "SnippetCardItem", + "OverviewCardBlock", + "OverviewCardItem", + "ContextCardBlock", + "ContextCardItem", + "CompositeCardBlock", + "CompositeCardItem", + "VisualCardBlock", + "VisualCardItem", + "Text", + "BoldText", + "IconText", + "ImageText", + "ImageTextLarge", + "MetricIndicatorInline", + "MetricIndicatorWithStrikethrough" + ], + "notes": [ + "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", + "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", + "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", + "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", + "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", + "- VisualCardItem: image-first card with a BoldText body and optional Tag.", + "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card." + ] + } + ] + }, + "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Content\nCardHeader(title?: string, subtitle?: string) — Header with optional title and subtitle\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nMarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\") — Renders markdown text with optional container variant\nCallout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding) — Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.\nTextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string) — Text callout with variant, title, and description\nImage(alt: string, src?: string) — Image with alt text and optional URL\nImageBlock(src: string, alt?: string) — Image block with loading state\nImageGallery(images: {src: string, alt?: string, details?: string}[]) — Gallery grid of images with modal preview\nCodeBlock(language: string, codeString: string) — Syntax-highlighted code block\nSeparator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean) — Visual divider between content sections\nInlineHeader(heading: string, description?: string) — Compact section heading with an optional one-line description, for use inside cards.\n- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).\n- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card.\n\n### Tables\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\nEditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[]) — Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field\n- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).\n- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.\n\n### Charts (2D)\nBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number) — Vertical bars; use for comparing values across categories with one or more series\nLineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Lines over categories; use for trends and continuous data over time\nAreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Filled area under lines; use for cumulative totals or volume trends over time\nRadarChart(labels: string[], series: Series[]) — Spider/web chart; use for comparing multiple variables across one or more entities\nHorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string) — Horizontal bars; prefer when category labels are long or for ranked lists\nSeries(category: string, values: number[]) — One data series\n\n### Charts (1D)\nPieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\") — Circular slices; use plucked arrays: PieChart(data.categories, data.values)\nRadialChart(labels: string[], values: number[]) — Radial bars; use plucked arrays: RadialChart(data.categories, data.values)\nSingleStackedBarChart(labels: string[], values: number[]) — Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)\nSlice(category: string, value: number) — One slice with label and numeric value\n\n### Charts (Scatter)\nScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string) — X/Y scatter plot; use for correlations, distributions, and clustering\nScatterSeries(name: string, points: Point[]) — Named dataset\nPoint(x: number, y: number, z?: number) — Data point with numeric coordinates\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nLabel(text: string) — Text label\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nTextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nDatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSlider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding) — Numeric slider input; supports continuous and discrete (stepped) variants\nCheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)\nCheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)\nRadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nRadioItem(label: string, description: string, value: string)\nSwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>) — Group of switch toggles\nSwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean) — Individual switch toggle\nChips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.\nChipItem(value: string, label: string, icon?: Icon, disabled?: boolean) — A single selectable chip inside a Chips group, with a value, label and optional icon.\nOptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.\nOptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean) — A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.\n- Chips: compact single/multiple selection pills. Use ChipItem references for each option.\n- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.\n- Define EACH FormControl as its own reference — do NOT inline all controls in one array.\n- NEVER nest Form inside Form.\n- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).\n- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }\n- The renderer shows error messages automatically — do NOT generate error text in the UI\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nIcon(name: string, category?: string) — A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.\nIconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\") — Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.\n- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.\n\n### Lists & Follow-ups\nListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\") — A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.\nListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression) — Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.\nFollowUpBlock(items: FollowUpItem[]) — List of clickable follow-up suggestions placed at the end of a response\nFollowUpItem(text: string) — Clickable follow-up suggestion — when clicked, sends text as user message\n- Use ListBlock with ListItem references for numbered lists.\n- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.\n- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.\n- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.\n- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })\n\n### Sections\nSectionBlock(sections: SectionItem[], isFoldable?: boolean) — Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section.\nSectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[]) — Section with a label and collapsible content — used inside SectionBlock\n- SectionBlock renders collapsible accordion sections that auto-open as they stream.\n- Each section needs a unique `value` id, a `trigger` label, and a `content` array.\n- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])\n- Set isFoldable=false to render sections as flat headers instead of accordion.\n\n### Layout\nTabs(items: TabItem[]) — Tabbed container\nTabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[]) — value is unique id, trigger is tab label, content is array of components\nAccordion(items: AccordionItem[]) — Collapsible sections\nAccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[]) — value is unique id, trigger is section title\nSteps(items: StepsItem[]) — Step-by-step guide\nStepsItem(title: string, details: string) — title and details text for one step\nCarousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\") — Horizontal scrollable carousel\n- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.\n- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])\n- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.\n- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.\n- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs.\n\n### Data Display\nTagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\") — tags is an array of strings; optional size sm | md | lg\nTag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\") — Styled tag/badge with optional Icon and variant\nEntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}) — Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.\n- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.\n\n### Cards\nSnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.\nSnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText) — One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).\nOverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.\nOverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline) — One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.\nContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.\nContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string) — A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.\nCompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.\nCompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button}) — A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.\nVisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.\nVisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string) — A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).\nText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nBoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nIconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\") — An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.\nImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number) — A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.\nImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean) — A full-width banner image above a bold title and optional subtitle. src must be a real image URL.\nMetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional +/- percentage trend and subtext, all on one line.\nMetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.\n- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.\n- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.\n- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.\n- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.\n- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.\n- VisualCardItem: image-first card with a BoldText body and optional Tag.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root." + }, + { + "name": "chat-options", + "spec": { + "root": "Card", + "components": { + "Card": { + "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", + "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." + }, + "CardHeader": { + "signature": "CardHeader(title?: string, subtitle?: string)", + "description": "Header with optional title and subtitle" + }, + "TextContent": { + "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "MarkDownRenderer": { + "signature": "MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")", + "description": "Renders markdown text with optional container variant" + }, + "Callout": { + "signature": "Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)", + "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." + }, + "TextCallout": { + "signature": "TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)", + "description": "Text callout with variant, title, and description" + }, + "Image": { + "signature": "Image(alt: string, src?: string)", + "description": "Image with alt text and optional URL" + }, + "ImageBlock": { + "signature": "ImageBlock(src: string, alt?: string)", + "description": "Image block with loading state" + }, + "ImageGallery": { + "signature": "ImageGallery(images: {src: string, alt?: string, details?: string}[])", + "description": "Gallery grid of images with modal preview" + }, + "CodeBlock": { + "signature": "CodeBlock(language: string, codeString: string)", + "description": "Syntax-highlighted code block" + }, + "Separator": { + "signature": "Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)", + "description": "Visual divider between content sections" + }, + "Table": { + "signature": "Table(columns: Col[])", + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", + "description": "Column definition — holds label + data array" + }, + "BarChart": { + "signature": "BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Vertical bars; use for comparing values across categories with one or more series" + }, + "LineChart": { + "signature": "LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Lines over categories; use for trends and continuous data over time" + }, + "AreaChart": { + "signature": "AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Filled area under lines; use for cumulative totals or volume trends over time" + }, + "RadarChart": { + "signature": "RadarChart(labels: string[], series: Series[])", + "description": "Spider/web chart; use for comparing multiple variables across one or more entities" + }, + "HorizontalBarChart": { + "signature": "HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)", + "description": "Horizontal bars; prefer when category labels are long or for ranked lists" + }, + "Series": { + "signature": "Series(category: string, values: number[])", + "description": "One data series" + }, + "PieChart": { + "signature": "PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")", + "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" + }, + "RadialChart": { + "signature": "RadialChart(labels: string[], values: number[])", + "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" + }, + "SingleStackedBarChart": { + "signature": "SingleStackedBarChart(labels: string[], values: number[])", + "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" + }, + "Slice": { + "signature": "Slice(category: string, value: number)", + "description": "One slice with label and numeric value" + }, + "ScatterChart": { + "signature": "ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)", + "description": "X/Y scatter plot; use for correlations, distributions, and clustering" + }, + "ScatterSeries": { + "signature": "ScatterSeries(name: string, points: Point[])", + "description": "Named dataset" + }, + "Point": { + "signature": "Point(x: number, y: number, z?: number)", + "description": "Data point with numeric coordinates" + }, + "Form": { + "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", + "description": "Form container with fields and explicit action buttons" + }, + "FormControl": { + "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", + "description": "Field with label, input component, and optional hint text" + }, + "Label": { + "signature": "Label(text: string)", + "description": "Text label" + }, + "Input": { + "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "TextArea": { + "signature": "TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Select": { + "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", + "description": "" + }, + "SelectItem": { + "signature": "SelectItem(value: string, label: string)", + "description": "Option for Select" + }, + "DatePicker": { + "signature": "DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Slider": { + "signature": "Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "Numeric slider input; supports continuous and discrete (stepped) variants" + }, + "CheckBoxGroup": { + "signature": "CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)", + "description": "" + }, + "CheckBoxItem": { + "signature": "CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)", + "description": "" + }, + "RadioGroup": { + "signature": "RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "RadioItem": { + "signature": "RadioItem(label: string, description: string, value: string)", + "description": "" + }, + "SwitchGroup": { + "signature": "SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)", + "description": "Group of switch toggles" + }, + "SwitchItem": { + "signature": "SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)", + "description": "Individual switch toggle" + }, + "Button": { + "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", + "description": "Clickable button" + }, + "Buttons": { + "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "ListBlock": { + "signature": "ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")", + "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." + }, + "ListItem": { + "signature": "ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)", + "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." + }, + "FollowUpBlock": { + "signature": "FollowUpBlock(items: FollowUpItem[])", + "description": "List of clickable follow-up suggestions placed at the end of a response" + }, + "FollowUpItem": { + "signature": "FollowUpItem(text: string)", + "description": "Clickable follow-up suggestion — when clicked, sends text as user message" + }, + "SectionBlock": { + "signature": "SectionBlock(sections: SectionItem[], isFoldable?: boolean)", + "description": "Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section." + }, + "SectionItem": { + "signature": "SectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[])", + "description": "Section with a label and collapsible content — used inside SectionBlock" + }, + "Tabs": { + "signature": "Tabs(items: TabItem[])", + "description": "Tabbed container" + }, + "TabItem": { + "signature": "TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[])", + "description": "value is unique id, trigger is tab label, content is array of components" + }, + "Accordion": { + "signature": "Accordion(items: AccordionItem[])", + "description": "Collapsible sections" + }, + "AccordionItem": { + "signature": "AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[])", + "description": "value is unique id, trigger is section title" + }, + "Steps": { + "signature": "Steps(items: StepsItem[])", + "description": "Step-by-step guide" + }, + "StepsItem": { + "signature": "StepsItem(title: string, details: string)", + "description": "title and details text for one step" + }, + "Carousel": { + "signature": "Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\")", + "description": "Horizontal scrollable carousel" + }, + "TagBlock": { + "signature": "TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")", + "description": "tags is an array of strings; optional size sm | md | lg" + }, + "Tag": { + "signature": "Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")", + "description": "Styled tag/badge with optional Icon and variant" + }, + "EntityList": { + "signature": "EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})", + "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." + }, + "InlineHeader": { + "signature": "InlineHeader(heading: string, description?: string)", + "description": "Compact section heading with an optional one-line description, for use inside cards." + }, + "Icon": { + "signature": "Icon(name: string, category?: string)", + "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." + }, + "IconButton": { + "signature": "IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")", + "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." + }, + "EditableTable": { + "signature": "EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])", + "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" + }, + "ChipItem": { + "signature": "ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)", + "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." + }, + "Chips": { + "signature": "Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", + "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." + }, + "OptionCard": { + "signature": "OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)", + "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." + }, + "OptionCards": { + "signature": "OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", + "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." + }, + "Text": { + "signature": "Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", + "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "BoldText": { + "signature": "BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", + "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "IconText": { + "signature": "IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")", + "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." + }, + "ImageText": { + "signature": "ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)", + "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." + }, + "ImageTextLarge": { + "signature": "ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)", + "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." + }, + "MetricIndicatorInline": { + "signature": "MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})", + "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." + }, + "MetricIndicatorWithStrikethrough": { + "signature": "MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})", + "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." + }, + "SnippetCardItem": { + "signature": "SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)", + "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." + }, + "SnippetCardBlock": { + "signature": "SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." + }, + "OverviewCardItem": { + "signature": "OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)", + "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." + }, + "OverviewCardBlock": { + "signature": "OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." + }, + "ContextCardItem": { + "signature": "ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)", + "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." + }, + "ContextCardBlock": { + "signature": "ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." + }, + "CompositeCardItem": { + "signature": "CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})", + "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." + }, + "CompositeCardBlock": { + "signature": "CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." + }, + "VisualCardItem": { + "signature": "VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)", + "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." + }, + "VisualCardBlock": { + "signature": "VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." + } + }, + "componentGroups": [ + { + "name": "Content", + "components": [ + "CardHeader", + "TextContent", + "MarkDownRenderer", + "Callout", + "TextCallout", + "Image", + "ImageBlock", + "ImageGallery", + "CodeBlock", + "Separator", + "InlineHeader" + ], + "notes": [ + "- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).", + "- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card." + ] + }, + { + "name": "Tables", + "components": [ + "Table", + "Col", + "EditableTable" + ], + "notes": [ + "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", + "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes." + ] + }, + { + "name": "Charts (2D)", + "components": [ + "BarChart", + "LineChart", + "AreaChart", + "RadarChart", + "HorizontalBarChart", + "Series" + ] + }, + { + "name": "Charts (1D)", + "components": [ + "PieChart", + "RadialChart", + "SingleStackedBarChart", + "Slice" + ] + }, + { + "name": "Charts (Scatter)", + "components": [ + "ScatterChart", + "ScatterSeries", + "Point" + ] + }, + { + "name": "Forms", + "components": [ + "Form", + "FormControl", + "Label", + "Input", + "TextArea", + "Select", + "SelectItem", + "DatePicker", + "Slider", + "CheckBoxGroup", + "CheckBoxItem", + "RadioGroup", + "RadioItem", + "SwitchGroup", + "SwitchItem", + "Chips", + "ChipItem", + "OptionCards", + "OptionCard" + ], + "notes": [ + "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", + "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", + "- Define EACH FormControl as its own reference — do NOT inline all controls in one array.", + "- NEVER nest Form inside Form.", + "- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).", + "- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }", + "- The renderer shows error messages automatically — do NOT generate error text in the UI" + ] + }, + { + "name": "Buttons", + "components": [ + "Button", + "Buttons", + "Icon", + "IconButton" + ], + "notes": [ + "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard." + ] + }, + { + "name": "Lists & Follow-ups", + "components": [ + "ListBlock", + "ListItem", + "FollowUpBlock", + "FollowUpItem" + ], + "notes": [ + "- Use ListBlock with ListItem references for numbered lists.", + "- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.", + "- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.", + "- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.", + "- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })" + ] + }, + { + "name": "Sections", + "components": [ + "SectionBlock", + "SectionItem" + ], + "notes": [ + "- SectionBlock renders collapsible accordion sections that auto-open as they stream.", + "- Each section needs a unique `value` id, a `trigger` label, and a `content` array.", + "- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])", + "- Set isFoldable=false to render sections as flat headers instead of accordion." + ] + }, + { + "name": "Layout", + "components": [ + "Tabs", + "TabItem", + "Accordion", + "AccordionItem", + "Steps", + "StepsItem", + "Carousel" + ], + "notes": [ + "- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.", + "- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])", + "- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.", + "- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.", + "- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs." + ] + }, + { + "name": "Data Display", + "components": [ + "TagBlock", + "Tag", + "EntityList" + ], + "notes": [ + "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not." + ] + }, + { + "name": "Cards", + "components": [ + "SnippetCardBlock", + "SnippetCardItem", + "OverviewCardBlock", + "OverviewCardItem", + "ContextCardBlock", + "ContextCardItem", + "CompositeCardBlock", + "CompositeCardItem", + "VisualCardBlock", + "VisualCardItem", + "Text", + "BoldText", + "IconText", + "ImageText", + "ImageTextLarge", + "MetricIndicatorInline", + "MetricIndicatorWithStrikethrough" + ], + "notes": [ + "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", + "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", + "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", + "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", + "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", + "- VisualCardItem: image-first card with a BoldText body and optional Tag.", + "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card." + ] + } + ], + "examples": [ + "Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }", + "Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")", + "Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)", + "Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }", + "Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")" + ], + "additionalRules": [ + "When asked about data, generate realistic/plausible data", + "Every response is a single Card(children) — children stack vertically automatically. No layout params are needed on Card.", + "Card is the only layout container. Do NOT use Stack. Use Tabs to switch between sections, Carousel for horizontal scroll.", + "Use FollowUpBlock at the END of a Card to suggest what the user can do or ask next.", + "Use ListBlock when presenting a set of options or steps; give each ListItem an action (5th argument) to make it clickable — without one the item is plain text.", + "Use SectionBlock to group long responses into collapsible sections — good for reports, FAQs, and structured content.", + "Use SectionItem inside SectionBlock: each item needs a unique value id, a trigger (header label), and a content array.", + "Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])", + "IMPORTANT: Every slide in a Carousel must use the same component structure in the same order — e.g. all slides: [title, image, description, tags].", + "For forms, define one FormControl reference per field so controls can stream progressively.", + "For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).", + "Never nest Form inside Form.", + "CardHeader is the page-level heading — place it as the first child of Card; InlineHeader is a lighter subsection label for a block inside the response, and is redundant when the following component already has a heading.", + "Never use Callout or TextCallout to justify why you did what you did or for any meta-information.", + "Every image slot (Image, ImageBlock, ImageGallery, VisualCardItem/ContextCardItem bgImageSrc, ImageText, ImageTextLarge, ListItem image) requires a REAL URL from a tool result, the conversation, or the user — NEVER invent, guess, or template a URL.", + "If no image URL is in context, compose without image components — icons, gray ContextCardItems, and charts still make rich layouts.", + "Argument-order trap: Image takes alt FIRST, while ImageBlock, ImageText, and ImageTextLarge take src FIRST — alt text in a src slot ships a broken image.", + "Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items, all with the same structure; use layout \"grid\" for primary side-by-side comparison and \"carousel\" for secondary browsing.", + "The card-block action is BLOCK-LEVEL: one action shared by every card, with the clicked card's details attached automatically — keep continue_conversation context generic (e.g. \"Tell me more about this destination\"), and never use a block-level open_url since it would send every card to the same URL.", + "Card items have NO per-item action: to give each item its own external link, use CompositeCardItem with footer { button: Button(label, { type: \"open_url\", url }) } — never claim a card opens a link it cannot.", + "Text, BoldText, IconText, ImageText, ImageTextLarge and MetricIndicator* are inline building blocks used INSIDE card items — do not place them directly in the root Card.", + "EntityList size \"small\" is reserved for CompositeCardItem body content (no header/footer); use size \"default\" elsewhere.", + "Tag variant must be semantically correct (success=positive, danger=negative, warning=cautionary, info=informational, neutral=label); Tag takes an optional Icon second, so use Tag(text, icon, size, variant) when a variant is needed.", + "TagBlock takes plain strings — keep it to at most 3 tags.", + "ListBlock variant \"number\" is for ordered sequences and rankings, \"image\" for products/profiles with a real image; Steps is for ordered sequential processes only.", + "Use SectionBlock to divide a long response into independent, equally prominent topics; use Tabs when the items are alternative views of the same thing; set isFoldable=false unless a section has 4+ distinct blocks; never make SectionBlock the first Card child.", + "Accordion is for supplementary or FAQ content only — never primary information, 3-5 items max, and always the last component in its section or card.", + "Charts: LineChart/AreaChart variant \"natural\" for smooth trends and \"linear\" for precise point-to-point data; BarChart \"grouped\" for side-by-side comparison and \"stacked\" for part-to-whole; prefer HorizontalBarChart when category labels are long or numerous.", + "For large chart values, scale the data and put the unit in the axis label (e.g. yLabel \"Revenue ($k)\") instead of passing raw thousands or millions.", + "Quantitative asks get a chart (plus KPI cards where useful) in the FIRST response — do not answer numbers with prose or a table alone.", + "Table is column-oriented: each Col holds its own data array of plain strings or numbers (never components), and every column's array must have the same length.", + "Use EditableTable ONLY when the user or app explicitly asks for an editable table; default to Table for read-only data.", + "Every Form MUST have EXACTLY ONE submit Button with variant \"primary\" — that button validates the form; other buttons (secondary/tertiary escape hatches like \"Just Surprise Me\") skip validation, and there is never a reset button.", + "Prefer structured inputs (Select, Chips, OptionCards, DatePicker, Slider) over free-text Input, give every FormControl a clear label (and a hint where it prevents mistakes), and keep each field name unique within the response.", + "Validation rules ({ required: true, email: true, minLength: 8, ... }) are enforced with inline errors — use them for genuinely essential fields, but never require a free-text field where leaving it blank is meaningful.", + "Form inputs work ONLY inside a FormControl within a Form; for tappable suggestion choices OUTSIDE a form, use Buttons of continue_conversation Buttons — never a bare OptionCards or Chips.", + "Only add Buttons for real actions: form submit, open_url with a URL from a tool or the user (never fabricated), or a continue_conversation follow-up — never a button for an app action (open, download, export, edit) you cannot perform.", + "Every Button label must accurately describe what clicking it does; use \"primary\" for the main action and \"secondary\"/\"tertiary\" only for lower-emphasis supporting actions.", + "Icon: always include the category argument — it enables fallback matching when the exact lucide name is unavailable.", + "Pass sources on Card ONLY when the answer relies on real references you actually have, and cite them inline in TextContent as [1], [2] (1-based index into sources)." + ] + }, + "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Content\nCardHeader(title?: string, subtitle?: string) — Header with optional title and subtitle\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nMarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\") — Renders markdown text with optional container variant\nCallout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding) — Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.\nTextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string) — Text callout with variant, title, and description\nImage(alt: string, src?: string) — Image with alt text and optional URL\nImageBlock(src: string, alt?: string) — Image block with loading state\nImageGallery(images: {src: string, alt?: string, details?: string}[]) — Gallery grid of images with modal preview\nCodeBlock(language: string, codeString: string) — Syntax-highlighted code block\nSeparator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean) — Visual divider between content sections\nInlineHeader(heading: string, description?: string) — Compact section heading with an optional one-line description, for use inside cards.\n- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).\n- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card.\n\n### Tables\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\nEditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[]) — Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field\n- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).\n- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.\n\n### Charts (2D)\nBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number) — Vertical bars; use for comparing values across categories with one or more series\nLineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Lines over categories; use for trends and continuous data over time\nAreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Filled area under lines; use for cumulative totals or volume trends over time\nRadarChart(labels: string[], series: Series[]) — Spider/web chart; use for comparing multiple variables across one or more entities\nHorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string) — Horizontal bars; prefer when category labels are long or for ranked lists\nSeries(category: string, values: number[]) — One data series\n\n### Charts (1D)\nPieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\") — Circular slices; use plucked arrays: PieChart(data.categories, data.values)\nRadialChart(labels: string[], values: number[]) — Radial bars; use plucked arrays: RadialChart(data.categories, data.values)\nSingleStackedBarChart(labels: string[], values: number[]) — Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)\nSlice(category: string, value: number) — One slice with label and numeric value\n\n### Charts (Scatter)\nScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string) — X/Y scatter plot; use for correlations, distributions, and clustering\nScatterSeries(name: string, points: Point[]) — Named dataset\nPoint(x: number, y: number, z?: number) — Data point with numeric coordinates\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nLabel(text: string) — Text label\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nTextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nDatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSlider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding) — Numeric slider input; supports continuous and discrete (stepped) variants\nCheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)\nCheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)\nRadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nRadioItem(label: string, description: string, value: string)\nSwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>) — Group of switch toggles\nSwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean) — Individual switch toggle\nChips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.\nChipItem(value: string, label: string, icon?: Icon, disabled?: boolean) — A single selectable chip inside a Chips group, with a value, label and optional icon.\nOptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.\nOptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean) — A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.\n- Chips: compact single/multiple selection pills. Use ChipItem references for each option.\n- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.\n- Define EACH FormControl as its own reference — do NOT inline all controls in one array.\n- NEVER nest Form inside Form.\n- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).\n- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }\n- The renderer shows error messages automatically — do NOT generate error text in the UI\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nIcon(name: string, category?: string) — A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.\nIconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\") — Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.\n- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.\n\n### Lists & Follow-ups\nListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\") — A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.\nListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression) — Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.\nFollowUpBlock(items: FollowUpItem[]) — List of clickable follow-up suggestions placed at the end of a response\nFollowUpItem(text: string) — Clickable follow-up suggestion — when clicked, sends text as user message\n- Use ListBlock with ListItem references for numbered lists.\n- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.\n- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.\n- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.\n- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })\n\n### Sections\nSectionBlock(sections: SectionItem[], isFoldable?: boolean) — Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section.\nSectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[]) — Section with a label and collapsible content — used inside SectionBlock\n- SectionBlock renders collapsible accordion sections that auto-open as they stream.\n- Each section needs a unique `value` id, a `trigger` label, and a `content` array.\n- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])\n- Set isFoldable=false to render sections as flat headers instead of accordion.\n\n### Layout\nTabs(items: TabItem[]) — Tabbed container\nTabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[]) — value is unique id, trigger is tab label, content is array of components\nAccordion(items: AccordionItem[]) — Collapsible sections\nAccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[]) — value is unique id, trigger is section title\nSteps(items: StepsItem[]) — Step-by-step guide\nStepsItem(title: string, details: string) — title and details text for one step\nCarousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\") — Horizontal scrollable carousel\n- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.\n- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])\n- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.\n- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.\n- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs.\n\n### Data Display\nTagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\") — tags is an array of strings; optional size sm | md | lg\nTag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\") — Styled tag/badge with optional Icon and variant\nEntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}) — Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.\n- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.\n\n### Cards\nSnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.\nSnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText) — One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).\nOverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.\nOverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline) — One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.\nContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.\nContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string) — A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.\nCompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.\nCompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button}) — A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.\nVisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.\nVisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string) — A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).\nText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nBoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nIconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\") — An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.\nImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number) — A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.\nImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean) — A full-width banner image above a bold title and optional subtitle. src must be a real image URL.\nMetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional +/- percentage trend and subtext, all on one line.\nMetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.\n- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.\n- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.\n- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.\n- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.\n- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.\n- VisualCardItem: image-first card with a BoldText body and optional Tag.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n\n## Examples\n\nExample 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }\n\nExample 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")\n\nExample 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)\n\nExample 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }\n\nExample 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")\n\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n\n- When asked about data, generate realistic/plausible data\n- Every response is a single Card(children) — children stack vertically automatically. No layout params are needed on Card.\n- Card is the only layout container. Do NOT use Stack. Use Tabs to switch between sections, Carousel for horizontal scroll.\n- Use FollowUpBlock at the END of a Card to suggest what the user can do or ask next.\n- Use ListBlock when presenting a set of options or steps; give each ListItem an action (5th argument) to make it clickable — without one the item is plain text.\n- Use SectionBlock to group long responses into collapsible sections — good for reports, FAQs, and structured content.\n- Use SectionItem inside SectionBlock: each item needs a unique value id, a trigger (header label), and a content array.\n- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])\n- IMPORTANT: Every slide in a Carousel must use the same component structure in the same order — e.g. all slides: [title, image, description, tags].\n- For forms, define one FormControl reference per field so controls can stream progressively.\n- For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).\n- Never nest Form inside Form.\n- CardHeader is the page-level heading — place it as the first child of Card; InlineHeader is a lighter subsection label for a block inside the response, and is redundant when the following component already has a heading.\n- Never use Callout or TextCallout to justify why you did what you did or for any meta-information.\n- Every image slot (Image, ImageBlock, ImageGallery, VisualCardItem/ContextCardItem bgImageSrc, ImageText, ImageTextLarge, ListItem image) requires a REAL URL from a tool result, the conversation, or the user — NEVER invent, guess, or template a URL.\n- If no image URL is in context, compose without image components — icons, gray ContextCardItems, and charts still make rich layouts.\n- Argument-order trap: Image takes alt FIRST, while ImageBlock, ImageText, and ImageTextLarge take src FIRST — alt text in a src slot ships a broken image.\n- Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items, all with the same structure; use layout \"grid\" for primary side-by-side comparison and \"carousel\" for secondary browsing.\n- The card-block action is BLOCK-LEVEL: one action shared by every card, with the clicked card's details attached automatically — keep continue_conversation context generic (e.g. \"Tell me more about this destination\"), and never use a block-level open_url since it would send every card to the same URL.\n- Card items have NO per-item action: to give each item its own external link, use CompositeCardItem with footer { button: Button(label, { type: \"open_url\", url }) } — never claim a card opens a link it cannot.\n- Text, BoldText, IconText, ImageText, ImageTextLarge and MetricIndicator* are inline building blocks used INSIDE card items — do not place them directly in the root Card.\n- EntityList size \"small\" is reserved for CompositeCardItem body content (no header/footer); use size \"default\" elsewhere.\n- Tag variant must be semantically correct (success=positive, danger=negative, warning=cautionary, info=informational, neutral=label); Tag takes an optional Icon second, so use Tag(text, icon, size, variant) when a variant is needed.\n- TagBlock takes plain strings — keep it to at most 3 tags.\n- ListBlock variant \"number\" is for ordered sequences and rankings, \"image\" for products/profiles with a real image; Steps is for ordered sequential processes only.\n- Use SectionBlock to divide a long response into independent, equally prominent topics; use Tabs when the items are alternative views of the same thing; set isFoldable=false unless a section has 4+ distinct blocks; never make SectionBlock the first Card child.\n- Accordion is for supplementary or FAQ content only — never primary information, 3-5 items max, and always the last component in its section or card.\n- Charts: LineChart/AreaChart variant \"natural\" for smooth trends and \"linear\" for precise point-to-point data; BarChart \"grouped\" for side-by-side comparison and \"stacked\" for part-to-whole; prefer HorizontalBarChart when category labels are long or numerous.\n- For large chart values, scale the data and put the unit in the axis label (e.g. yLabel \"Revenue ($k)\") instead of passing raw thousands or millions.\n- Quantitative asks get a chart (plus KPI cards where useful) in the FIRST response — do not answer numbers with prose or a table alone.\n- Table is column-oriented: each Col holds its own data array of plain strings or numbers (never components), and every column's array must have the same length.\n- Use EditableTable ONLY when the user or app explicitly asks for an editable table; default to Table for read-only data.\n- Every Form MUST have EXACTLY ONE submit Button with variant \"primary\" — that button validates the form; other buttons (secondary/tertiary escape hatches like \"Just Surprise Me\") skip validation, and there is never a reset button.\n- Prefer structured inputs (Select, Chips, OptionCards, DatePicker, Slider) over free-text Input, give every FormControl a clear label (and a hint where it prevents mistakes), and keep each field name unique within the response.\n- Validation rules ({ required: true, email: true, minLength: 8, ... }) are enforced with inline errors — use them for genuinely essential fields, but never require a free-text field where leaving it blank is meaningful.\n- Form inputs work ONLY inside a FormControl within a Form; for tappable suggestion choices OUTSIDE a form, use Buttons of continue_conversation Buttons — never a bare OptionCards or Chips.\n- Only add Buttons for real actions: form submit, open_url with a URL from a tool or the user (never fabricated), or a continue_conversation follow-up — never a button for an app action (open, download, export, edit) you cannot perform.\n- Every Button label must accurately describe what clicking it does; use \"primary\" for the main action and \"secondary\"/\"tertiary\" only for lower-emphasis supporting actions.\n- Icon: always include the category argument — it enables fallback matching when the exact lucide name is unavailable.\n- Pass sources on Card ONLY when the answer relies on real references you actually have, and cite them inline in TextContent as [1], [2] (1-based index into sources)." + }, + { + "name": "slice-bindings", + "spec": { + "root": "Card", + "components": { + "Card": { + "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", + "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." + }, + "TextContent": { + "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "Button": { + "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", + "description": "Clickable button" + }, + "Buttons": { + "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "Form": { + "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", + "description": "Form container with fields and explicit action buttons" + }, + "FormControl": { + "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", + "description": "Field with label, input component, and optional hint text" + }, + "Input": { + "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Select": { + "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", + "description": "" + }, + "SelectItem": { + "signature": "SelectItem(value: string, label: string)", + "description": "Option for Select" + }, + "Table": { + "signature": "Table(columns: Col[])", + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", + "description": "Column definition — holds label + data array" + } + }, + "componentGroups": [ + { + "name": "Forms", + "components": [ + "Form", + "FormControl", + "Input", + "Select", + "SelectItem" + ], + "notes": [ + "- Forms note" + ] + }, + { + "name": "Buttons", + "components": [ + "Button", + "Buttons", + "Missing" + ] + } + ], + "bindings": true + }, + "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n8. Declare mutable state with `$varName = defaultValue`. Components marked with `$binding` can read/write these. Undeclared $variables are auto-created with null default.\n9. String concatenation: `\"text\" + $var + \"more\"`\n10. Dot member access: `query.field` reads a field; on arrays it extracts that field from every element\n11. Index access: `arr[0]`, `data[index]`\n12. Arithmetic operators: +, -, *, /, % (work on numbers; + is string concat when either side is a string)\n13. Comparison: ==, !=, >, <, >=, <=\n14. Logical: &&, ||, ! (prefix)\n15. Ternary: `condition ? valueIfTrue : valueIfFalse`\n16. Parentheses for grouping: `(a + b) * c`\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl, @Set, @Reset).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\n- Forms note\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Built-in Functions\n\nData functions prefixed with `@` to distinguish from components. These are the ONLY functions available — do NOT invent new ones.\nUse @-prefixed built-in functions (@Count, @Sum, @Avg, @Min, @Max, @Round) on Query results — do NOT hardcode computed values.\n\n@Count(array) → number — Returns array length\n@First(array) → element — Returns first element of array\n@Last(array) → element — Returns last element of array\n@Sum(numbers[]) → number — Sum of numeric array\n@Avg(numbers[]) → number — Average of numeric array\n@Min(numbers[]) → number — Minimum value in array\n@Max(numbers[]) → number — Maximum value in array\n@Sort(array, field, direction?) → sorted array — Sort array by field. Direction: \"asc\" (default) or \"desc\"\n@Filter(array, field, operator: \"==\" | \"!=\" | \">\" | \"<\" | \">=\" | \"<=\" | \"contains\", value) → filtered array — Filter array by field value\n@Round(number, decimals?) → number — Round to N decimal places (default 0)\n@Abs(number) → number — Absolute value\n@Floor(number) → number — Round down to nearest integer\n@Ceil(number) → number — Round up to nearest integer\n@Each(array, varName, template) — Evaluate template for each element. varName is the loop variable — use it ONLY inside the template expression (inline). Do NOT create a separate statement for the template.\n\nBuiltins compose — output of one is input to the next:\n`@Count(@Filter(data.rows, \"field\", \"==\", \"val\"))` for KPIs/chart values, `@Round(@Avg(data.rows.score), 1)`, `@Each(data.rows, \"item\", Comp(item.field))` for per-item rendering.\nArray pluck: `data.rows.field` extracts a field from every row → use with @Sum, @Avg, charts, tables.\n\nIMPORTANT @Each rule: The loop variable (e.g. \"item\") is ONLY available inside the @Each template expression. Always inline the template — do NOT extract it to a separate statement.\nCORRECT: `Col(\"Actions\", @Each(rows, \"t\", Button(\"Edit\", Action([@Set($id, t.id)]))))`\nWRONG: `myBtn = Button(\"Edit\", Action([@Set($id, t.id)]))` then `Col(\"Actions\", @Each(rows, \"t\", myBtn))` — t is undefined in myBtn.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n- @Set($variable, value) — Set a $variable to a specific value\n- @Reset($var1, $var2, ...) — Reset $variables to their declared defaults (e.g. @Reset($title, $priority) restores $title=\"\" and $priority=\"medium\")\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. $variable declarations — state ready for bindings\n3. Query statements — defaults resolve immediately so components render with data\n4. Component definitions — fill in with data already available\n5. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n3. Every $binding appears in at least one component or expression." + }, + { + "name": "slice-tools", + "spec": { + "root": "Card", + "components": { + "Card": { + "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", + "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." + }, + "TextContent": { + "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "Button": { + "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", + "description": "Clickable button" + }, + "Buttons": { + "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "Form": { + "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", + "description": "Form container with fields and explicit action buttons" + }, + "FormControl": { + "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", + "description": "Field with label, input component, and optional hint text" + }, + "Input": { + "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Select": { + "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", + "description": "" + }, + "SelectItem": { + "signature": "SelectItem(value: string, label: string)", + "description": "Option for Select" + }, + "Table": { + "signature": "Table(columns: Col[])", + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", + "description": "Column definition — holds label + data array" + } + }, + "componentGroups": [ + { + "name": "Forms", + "components": [ + "Form", + "FormControl", + "Input", + "Select", + "SelectItem" + ], + "notes": [ + "- Forms note" + ] + }, + { + "name": "Buttons", + "components": [ + "Button", + "Buttons", + "Missing" + ] + } + ], + "tools": [ + "search_docs", + { + "name": "list_tickets", + "description": "Open support tickets", + "inputSchema": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "open", + "closed" + ] + }, + "limit": { + "type": "number" + } + }, + "required": [ + "status" + ] + }, + "outputSchema": { + "type": "object", + "properties": { + "rows": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + } + }, + "total": { + "type": "integer" + } + } + } + }, + { + "name": "ping", + "inputSchema": {} + } + ], + "toolExamples": [ + "x = Query(\"list_tickets\", {status: \"open\"}, {rows: []})" + ] + }, + "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n8. Declare mutable state with `$varName = defaultValue`. Components marked with `$binding` can read/write these. Undeclared $variables are auto-created with null default.\n9. String concatenation: `\"text\" + $var + \"more\"`\n10. Dot member access: `query.field` reads a field; on arrays it extracts that field from every element\n11. Index access: `arr[0]`, `data[index]`\n12. Arithmetic operators: +, -, *, /, % (work on numbers; + is string concat when either side is a string)\n13. Comparison: ==, !=, >, <, >=, <=\n14. Logical: &&, ||, ! (prefix)\n15. Ternary: `condition ? valueIfTrue : valueIfFalse`\n16. Parentheses for grouping: `(a + b) * c`\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@Run, @ToAssistant, @OpenUrl, @Set, @Reset).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\n- Forms note\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Built-in Functions\n\nData functions prefixed with `@` to distinguish from components. These are the ONLY functions available — do NOT invent new ones.\nUse @-prefixed built-in functions (@Count, @Sum, @Avg, @Min, @Max, @Round) on Query results — do NOT hardcode computed values.\n\n@Count(array) → number — Returns array length\n@First(array) → element — Returns first element of array\n@Last(array) → element — Returns last element of array\n@Sum(numbers[]) → number — Sum of numeric array\n@Avg(numbers[]) → number — Average of numeric array\n@Min(numbers[]) → number — Minimum value in array\n@Max(numbers[]) → number — Maximum value in array\n@Sort(array, field, direction?) → sorted array — Sort array by field. Direction: \"asc\" (default) or \"desc\"\n@Filter(array, field, operator: \"==\" | \"!=\" | \">\" | \"<\" | \">=\" | \"<=\" | \"contains\", value) → filtered array — Filter array by field value\n@Round(number, decimals?) → number — Round to N decimal places (default 0)\n@Abs(number) → number — Absolute value\n@Floor(number) → number — Round down to nearest integer\n@Ceil(number) → number — Round up to nearest integer\n@Each(array, varName, template) — Evaluate template for each element. varName is the loop variable — use it ONLY inside the template expression (inline). Do NOT create a separate statement for the template.\n\nBuiltins compose — output of one is input to the next:\n`@Count(@Filter(data.rows, \"field\", \"==\", \"val\"))` for KPIs/chart values, `@Round(@Avg(data.rows.score), 1)`, `@Each(data.rows, \"item\", Comp(item.field))` for per-item rendering.\nArray pluck: `data.rows.field` extracts a field from every row → use with @Sum, @Avg, charts, tables.\n\nIMPORTANT @Each rule: The loop variable (e.g. \"item\") is ONLY available inside the @Each template expression. Always inline the template — do NOT extract it to a separate statement.\nCORRECT: `Col(\"Actions\", @Each(rows, \"t\", Button(\"Edit\", Action([@Set($id, t.id)]))))`\nWRONG: `myBtn = Button(\"Edit\", Action([@Set($id, t.id)]))` then `Col(\"Actions\", @Each(rows, \"t\", myBtn))` — t is undefined in myBtn.\n\n## Query — Live Data Fetching\n\nFetch data from available tools. Returns defaults instantly, swaps in real data when it arrives.\n\n```\nmetrics = Query(\"tool_name\", {arg1: value, arg2: $binding}, {defaultField: 0, defaultData: []}, refreshInterval?)\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (may reference $bindings — re-fetches automatically on change)\n- Third arg: default data (rendered immediately before fetch resolves)\n- Fourth arg (optional): refresh interval in seconds (e.g. 30 for auto-refresh every 30s)\n- Use dot access on results: metrics.totalEvents, metrics.data.day (array pluck)\n- Query results must use regular identifiers: `metrics = Query(...)`, NOT `$metrics = Query(...)`\n- Manual refresh: `Button(\"Refresh\", Action([@Run(query1), @Run(query2)]), \"secondary\")` — re-fetches the listed queries\n- Refresh all queries: create Action with @Run for each query\n\n## Mutation — Write Operations\n\nExecute state-changing tool calls (create, update, delete). Unlike Query (auto-fetches on render), Mutation fires only on button click via Action.\n\n```\nresult = Mutation(\"tool_name\", {arg1: $binding, arg2: \"value\"})\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (evaluated with current $binding values at click time)\n- result.status: \"idle\" | \"loading\" | \"success\" | \"error\"\n- result.data: tool response on success\n- result.error: error message on failure\n- Mutation results use regular identifiers: `result = Mutation(...)`, NOT `$result`\n- Show loading state: `result.status == \"loading\" ? TextContent(\"Saving...\") : null`\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @Run(queryOrMutationRef) — Execute a Mutation or re-fetch a Query (ref must be a declared Query/Mutation)\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n- @Set($variable, value) — Set a $variable to a specific value\n- @Reset($var1, $var2, ...) — Reset $variables to their declared defaults (e.g. @Reset($title, $priority) restores $title=\"\" and $priority=\"medium\")\n\nExample — mutation + refresh + reset (PREFERRED pattern):\n```\n$binding = \"default\"\nresult = Mutation(\"tool_name\", {field: $binding})\ndata = Query(\"tool_name\", {}, {rows: []})\nonSubmit = Action([@Run(result), @Run(data), @Reset($binding)])\n```\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n- If a @Run(mutation) step fails, remaining steps are skipped (halt on failure)\n- @Run(queryRef) re-fetches the query (fire-and-forget, cannot fail)\n\n## Interactive Filters\n\nTo let the user filter data with a dropdown:\n1. Declare a $variable with a default: `$dateRange = \"14\"`\n2. Create a Select with name, items, and binding: `Select(\"dateRange\", [SelectItem(\"7\", \"Last 7 days\"), ...], null, null, $dateRange)`\n3. Wrap in FormControl for a label: `FormControl(\"Date Range\", Select(...))`\n4. Pass $dateRange in Query args: `Query(\"tool\", {dateRange: $dateRange}, {defaults})`\n5. When the user changes the Select, $dateRange updates and the Query automatically re-fetches\n\nFILTER WIRING RULE: If a $binding filter is visible in the UI, EVERY relevant Query MUST reference that $binding in its args. Never show a filter dropdown while hardcoding the query args.\n\nRules for $variables:\n- $variables hold simple values (strings or numbers), NOT arrays or objects\n- $variables must be bound to a Select/Input component via the value argument (last positional arg) to be interactive\n- Queries must use regular identifiers (NOT $variables): `metrics = Query(...)` not `$metrics = Query(...)`\n- **Auto-declare**: You do NOT need to explicitly declare $variables. If you use `$foo` without declaring it, the parser auto-creates `$foo = null`. You can still declare explicitly to set a default: `$days = \"14\"`\n\n## Forms\n\nSimple form — no $bindings needed. Field values are managed internally by the Form via the name prop:\n```\ncontactForm = Form(\"contact\", submitBtn, [nameField, emailField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", {required: true}))\nemailField = FormControl(\"Email\", Input(\"email\", \"your@email.com\", \"email\", {required: true, email: true}))\nsubmitBtn = Button(\"Submit\")\n```\n\nUse $bindings when you need to read field values elsewhere (in Action context, Query args, or conditionals). They are auto-declared:\n```\n$role = \"engineer\"\ncontactForm = Form(\"contact\", submitBtn, [nameField, emailField, roleField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Enter your name\", \"text\", {required: true}, $name))\nemailField = FormControl(\"Email\", Input(\"email\", \"Enter your email\", \"email\", {required: true, email: true}, $email))\nroleField = FormControl(\"Role\", Select(\"role\", [SelectItem(\"engineer\", \"Engineer\"), SelectItem(\"designer\", \"Designer\"), SelectItem(\"pm\", \"PM\")], null, {required: true}, $role))\nsubmitBtn = Button(\"Submit\")\n```\n\nFor form + mutation patterns (create, refresh, reset), see the Action section example above.\n\nIMPORTANT: Always add validation rules to form fields used with Mutations. Use OBJECT syntax: {required: true, email: true, minLength: 8}. The renderer shows error messages automatically and blocks submit when validation fails.\n\n## Data Workflow\n\nWhen tools are available, follow this workflow:\n1. FIRST: Call the most relevant tool to inspect the real data shape before generating code\n2. Use Query() for READ operations (data that should stay live) — NEVER hardcode tool results as literal arrays or objects\n3. Use Mutation() for WRITE operations (create, update, delete) — triggered by button clicks via Action([@Run(mutationRef)])\n4. Use the real data from step 1 as condensed Query defaults (3-5 rows) so the UI renders immediately\n5. Use @-prefixed builtins (@Count, @Filter, @Sort, @Sum) on Query results for KPIs and aggregations — the runtime evaluates these live on every refresh\n6. Hardcoded arrays are ONLY for static display data (labels, options) where no tool exists\n\nWRONG — you called a tool and got data back, but you inlined the results:\n```\nopenCount = 2\nitem1 = SomeComp(\"first item title\")\nitem2 = SomeComp(\"second item title\")\nlist = SomeList([item1, item2])\nchart = SomeChart([\"A\", \"B\"], [12, 8])\n```\nThis is static — it shows stale data and won't update. Creating item1, item2, item3... manually is ALWAYS wrong when a tool exists.\n\nRIGHT — use Query() for live data, Mutation() for writes, @builtins to derive values:\n```\ndata = Query(\"tool_name\", {}, {rows: []})\nopenCount = @Count(@Filter(data.rows, \"field\", \"==\", \"value\"))\nlist = @Each(data.rows, \"item\", SomeComp(item.title, item.field))\ncreateResult = Mutation(\"create_tool\", {title: $title})\nsubmitBtn = Button(\"Create\", Action([@Run(createResult), @Run(data), @Reset($title)]))\n```\nEverything derives from the Query — when data refreshes, the entire dashboard updates automatically.\n\n## Available Tools\n\nUse these with Query() for read operations or Mutation() for write operations. The LLM decides which is appropriate based on the tool's purpose.\n\n- search_docs\n- list_tickets(status: \"open\" | \"closed\", limit?: number) → {rows?: {id?: string}[], total?: number}\n Open support tickets\n- ping()\n\n### Default values for Query results\n\nUse these shapes as minimal Query defaults:\n- list_tickets: `{\"rows\":[],\"total\":0}`\n\nCRITICAL: Use ONLY the tools listed above in Query() and Mutation() calls. Do NOT invent or guess tool names. If the user asks for functionality that doesn't match any available tool, use realistic mock data instead of fabricating a tool call.\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. $variable declarations — state ready for bindings\n3. Query statements — defaults resolve immediately so components render with data\n4. Component definitions — fill in with data already available\n5. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n\n## Examples\n\nx = Query(\"list_tickets\", {status: \"open\"}, {rows: []})\n\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n3. Every Query result is referenced by at least one component.\n4. Every $binding appears in at least one component or expression.\n5. Every visible filter $binding appears in at least one Query args object." + }, + { + "name": "slice-tools-no-bindings", + "spec": { + "root": "Card", + "components": { + "Card": { + "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", + "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." + }, + "TextContent": { + "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "Button": { + "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", + "description": "Clickable button" + }, + "Buttons": { + "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "Form": { + "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", + "description": "Form container with fields and explicit action buttons" + }, + "FormControl": { + "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", + "description": "Field with label, input component, and optional hint text" + }, + "Input": { + "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Select": { + "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", + "description": "" + }, + "SelectItem": { + "signature": "SelectItem(value: string, label: string)", + "description": "Option for Select" + }, + "Table": { + "signature": "Table(columns: Col[])", + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", + "description": "Column definition — holds label + data array" + } + }, + "componentGroups": [ + { + "name": "Forms", + "components": [ + "Form", + "FormControl", + "Input", + "Select", + "SelectItem" + ], + "notes": [ + "- Forms note" + ] + }, + { + "name": "Buttons", + "components": [ + "Button", + "Buttons", + "Missing" + ] + } + ], + "tools": [ + "search_docs", + { + "name": "list_tickets", + "description": "Open support tickets", + "inputSchema": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "open", + "closed" + ] + }, + "limit": { + "type": "number" + } + }, + "required": [ + "status" + ] + }, + "outputSchema": { + "type": "object", + "properties": { + "rows": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + } + }, + "total": { + "type": "integer" + } + } + } + }, + { + "name": "ping", + "inputSchema": {} + } + ], + "bindings": false + }, + "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n8. String concatenation: `\"text\" + $var + \"more\"`\n9. Dot member access: `query.field` reads a field; on arrays it extracts that field from every element\n10. Index access: `arr[0]`, `data[index]`\n11. Arithmetic operators: +, -, *, /, % (work on numbers; + is string concat when either side is a string)\n12. Comparison: ==, !=, >, <, >=, <=\n13. Logical: &&, ||, ! (prefix)\n14. Ternary: `condition ? valueIfTrue : valueIfFalse`\n15. Parentheses for grouping: `(a + b) * c`\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@Run, @ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\n- Forms note\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Built-in Functions\n\nData functions prefixed with `@` to distinguish from components. These are the ONLY functions available — do NOT invent new ones.\nUse @-prefixed built-in functions (@Count, @Sum, @Avg, @Min, @Max, @Round) on Query results — do NOT hardcode computed values.\n\n@Count(array) → number — Returns array length\n@First(array) → element — Returns first element of array\n@Last(array) → element — Returns last element of array\n@Sum(numbers[]) → number — Sum of numeric array\n@Avg(numbers[]) → number — Average of numeric array\n@Min(numbers[]) → number — Minimum value in array\n@Max(numbers[]) → number — Maximum value in array\n@Sort(array, field, direction?) → sorted array — Sort array by field. Direction: \"asc\" (default) or \"desc\"\n@Filter(array, field, operator: \"==\" | \"!=\" | \">\" | \"<\" | \">=\" | \"<=\" | \"contains\", value) → filtered array — Filter array by field value\n@Round(number, decimals?) → number — Round to N decimal places (default 0)\n@Abs(number) → number — Absolute value\n@Floor(number) → number — Round down to nearest integer\n@Ceil(number) → number — Round up to nearest integer\n@Each(array, varName, template) — Evaluate template for each element. varName is the loop variable — use it ONLY inside the template expression (inline). Do NOT create a separate statement for the template.\n\nBuiltins compose — output of one is input to the next:\n`@Count(@Filter(data.rows, \"field\", \"==\", \"val\"))` for KPIs/chart values, `@Round(@Avg(data.rows.score), 1)`, `@Each(data.rows, \"item\", Comp(item.field))` for per-item rendering.\nArray pluck: `data.rows.field` extracts a field from every row → use with @Sum, @Avg, charts, tables.\n\nIMPORTANT @Each rule: The loop variable (e.g. \"item\") is ONLY available inside the @Each template expression. Always inline the template — do NOT extract it to a separate statement.\nCORRECT: `Col(\"Actions\", @Each(rows, \"t\", Button(\"Edit\", Action([@Set($id, t.id)]))))`\nWRONG: `myBtn = Button(\"Edit\", Action([@Set($id, t.id)]))` then `Col(\"Actions\", @Each(rows, \"t\", myBtn))` — t is undefined in myBtn.\n\n## Query — Live Data Fetching\n\nFetch data from available tools. Returns defaults instantly, swaps in real data when it arrives.\n\n```\nmetrics = Query(\"tool_name\", {arg1: value, arg2: $binding}, {defaultField: 0, defaultData: []}, refreshInterval?)\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (may reference $bindings — re-fetches automatically on change)\n- Third arg: default data (rendered immediately before fetch resolves)\n- Fourth arg (optional): refresh interval in seconds (e.g. 30 for auto-refresh every 30s)\n- Use dot access on results: metrics.totalEvents, metrics.data.day (array pluck)\n- Query results must use regular identifiers: `metrics = Query(...)`, NOT `$metrics = Query(...)`\n- Manual refresh: `Button(\"Refresh\", Action([@Run(query1), @Run(query2)]), \"secondary\")` — re-fetches the listed queries\n- Refresh all queries: create Action with @Run for each query\n\n## Mutation — Write Operations\n\nExecute state-changing tool calls (create, update, delete). Unlike Query (auto-fetches on render), Mutation fires only on button click via Action.\n\n```\nresult = Mutation(\"tool_name\", {arg1: $binding, arg2: \"value\"})\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (evaluated with current $binding values at click time)\n- result.status: \"idle\" | \"loading\" | \"success\" | \"error\"\n- result.data: tool response on success\n- result.error: error message on failure\n- Mutation results use regular identifiers: `result = Mutation(...)`, NOT `$result`\n- Show loading state: `result.status == \"loading\" ? TextContent(\"Saving...\") : null`\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @Run(queryOrMutationRef) — Execute a Mutation or re-fetch a Query (ref must be a declared Query/Mutation)\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — mutation + refresh + reset (PREFERRED pattern):\n```\n$binding = \"default\"\nresult = Mutation(\"tool_name\", {field: $binding})\ndata = Query(\"tool_name\", {}, {rows: []})\nonSubmit = Action([@Run(result), @Run(data), @Reset($binding)])\n```\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n- If a @Run(mutation) step fails, remaining steps are skipped (halt on failure)\n- @Run(queryRef) re-fetches the query (fire-and-forget, cannot fail)\n\n## Data Workflow\n\nWhen tools are available, follow this workflow:\n1. FIRST: Call the most relevant tool to inspect the real data shape before generating code\n2. Use Query() for READ operations (data that should stay live) — NEVER hardcode tool results as literal arrays or objects\n3. Use Mutation() for WRITE operations (create, update, delete) — triggered by button clicks via Action([@Run(mutationRef)])\n4. Use the real data from step 1 as condensed Query defaults (3-5 rows) so the UI renders immediately\n5. Use @-prefixed builtins (@Count, @Filter, @Sort, @Sum) on Query results for KPIs and aggregations — the runtime evaluates these live on every refresh\n6. Hardcoded arrays are ONLY for static display data (labels, options) where no tool exists\n\nWRONG — you called a tool and got data back, but you inlined the results:\n```\nopenCount = 2\nitem1 = SomeComp(\"first item title\")\nitem2 = SomeComp(\"second item title\")\nlist = SomeList([item1, item2])\nchart = SomeChart([\"A\", \"B\"], [12, 8])\n```\nThis is static — it shows stale data and won't update. Creating item1, item2, item3... manually is ALWAYS wrong when a tool exists.\n\nRIGHT — use Query() for live data, Mutation() for writes, @builtins to derive values:\n```\ndata = Query(\"tool_name\", {}, {rows: []})\nopenCount = @Count(@Filter(data.rows, \"field\", \"==\", \"value\"))\nlist = @Each(data.rows, \"item\", SomeComp(item.title, item.field))\ncreateResult = Mutation(\"create_tool\", {title: $title})\nsubmitBtn = Button(\"Create\", Action([@Run(createResult), @Run(data), @Reset($title)]))\n```\nEverything derives from the Query — when data refreshes, the entire dashboard updates automatically.\n\n## Available Tools\n\nUse these with Query() for read operations or Mutation() for write operations. The LLM decides which is appropriate based on the tool's purpose.\n\n- search_docs\n- list_tickets(status: \"open\" | \"closed\", limit?: number) → {rows?: {id?: string}[], total?: number}\n Open support tickets\n- ping()\n\n### Default values for Query results\n\nUse these shapes as minimal Query defaults:\n- list_tickets: `{\"rows\":[],\"total\":0}`\n\nCRITICAL: Use ONLY the tools listed above in Query() and Mutation() calls. Do NOT invent or guess tool names. If the user asks for functionality that doesn't match any available tool, use realistic mock data instead of fabricating a tool call.\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. $variable declarations — state ready for bindings\n3. Query statements — defaults resolve immediately so components render with data\n4. Component definitions — fill in with data already available\n5. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n3. Every Query result is referenced by at least one component." + }, + { + "name": "slice-modes", + "spec": { + "root": "Card", + "components": { + "Card": { + "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", + "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." + }, + "TextContent": { + "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "Button": { + "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", + "description": "Clickable button" + }, + "Buttons": { + "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "Form": { + "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", + "description": "Form container with fields and explicit action buttons" + }, + "FormControl": { + "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", + "description": "Field with label, input component, and optional hint text" + }, + "Input": { + "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Select": { + "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", + "description": "" + }, + "SelectItem": { + "signature": "SelectItem(value: string, label: string)", + "description": "Option for Select" + }, + "Table": { + "signature": "Table(columns: Col[])", + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", + "description": "Column definition — holds label + data array" + } + }, + "componentGroups": [ + { + "name": "Forms", + "components": [ + "Form", + "FormControl", + "Input", + "Select", + "SelectItem" + ], + "notes": [ + "- Forms note" + ] + }, + { + "name": "Buttons", + "components": [ + "Button", + "Buttons", + "Missing" + ] + } + ], + "editMode": true, + "inlineMode": true, + "preamble": "Custom preamble.", + "additionalRules": [ + "Be brief" + ], + "examples": [ + "a = 1" + ] + }, + "expected": "Custom preamble.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\n- Forms note\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n\n## Examples\n\na = 1\n\n\n## Edit Mode\n\nThe runtime merges by statement name: same name = replace, new name = append.\nOutput ONLY statements that changed or are new. Everything else is kept automatically.\n\n### Delete\nTo remove a component, re-declare its parent without that component in the parent's children array. The removed component and any statements only it referenced are automatically garbage-collected.\n\n### Patch size guide\n- Changing a title or label: 1 statement\n- Adding a component: 2-3 statements (the new component + parent update)\n- Removing a component: 1 statement (re-declare parent without the removed child)\n- Adding a filter + wiring to query: 3-5 statements\n- Restructuring into tabs: 5-10 statements\n\n### Rules\n- Reuse existing statement names exactly — do not rename\n- Do NOT re-emit unchanged statements — the runtime keeps them\n- A typical edit patch is 1-10 statements, not 20+\n- If the existing code already satisfies the request, output only the root statement\n- NEVER output the entire program as a patch. Only output what actually changes\n- If you are about to output more than 10 statements, reconsider — most edits need fewer\n\n## Inline Mode\n\nYou are in inline mode. You can respond in two ways:\n\n### 1. Code response (when the user wants to CREATE or CHANGE the UI)\nWrap openui-lang code in triple-backtick fences. You can include explanatory text before/after:\n\nHere's your dashboard:\n\n```openui-lang\nroot = RootComp([header, content])\nheader = SomeHeader(\"Title\")\ncontent = SomeContent(\"Hello world\")\n```\n\nI created a simple layout with a header.\n\n### 2. Text-only response (when the user asks a QUESTION)\nIf the user asks \"what is this?\", \"explain the chart\", \"how does this work\", etc. — respond with plain text. Do NOT output any openui-lang code. The existing dashboard stays unchanged.\n\n### Rules\n- When the user asks for changes, output ONLY the changed/new statements in a fenced block\n- When the user asks a question, respond with text only — NO code. The dashboard stays unchanged.\n- The parser extracts code from fences automatically. Text outside fences is shown as chat.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n\n- Be brief" + }, + { + "name": "slice-no-groups", + "spec": { + "root": "Card", + "components": { + "Card": { + "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", + "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." + }, + "TextContent": { + "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "Button": { + "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", + "description": "Clickable button" + }, + "Buttons": { + "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "Form": { + "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", + "description": "Form container with fields and explicit action buttons" + }, + "FormControl": { + "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", + "description": "Field with label, input component, and optional hint text" + }, + "Input": { + "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Select": { + "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", + "description": "" + }, + "SelectItem": { + "signature": "SelectItem(value: string, label: string)", + "description": "Option for Select" + }, + "Table": { + "signature": "Table(columns: Col[])", + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", + "description": "Column definition — holds label + data array" + } + } + }, + "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root." + }, + { + "name": "small-no-root", + "spec": { + "components": { + "Box": { + "signature": "Box(children: (Text | Box)[])", + "description": "A box" + }, + "Text": { + "signature": "Text(value: string, tone?: \"a\" | \"b\")" + } + } + }, + "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Root(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\n\nBox(children: (Text | Box)[]) — A box\nText(value: string, tone?: \"a\" | \"b\")\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Root(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Root(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Root(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root." + }, + { + "name": "small-tools-only", + "spec": { + "components": { + "Box": { + "signature": "Box(children: (Text | Box)[])", + "description": "A box" + }, + "Text": { + "signature": "Text(value: string, tone?: \"a\" | \"b\")" + } + }, + "toolCalls": true, + "bindings": false + }, + "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Root(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n8. String concatenation: `\"text\" + $var + \"more\"`\n9. Dot member access: `query.field` reads a field; on arrays it extracts that field from every element\n10. Index access: `arr[0]`, `data[index]`\n11. Arithmetic operators: +, -, *, /, % (work on numbers; + is string concat when either side is a string)\n12. Comparison: ==, !=, >, <, >=, <=\n13. Logical: &&, ||, ! (prefix)\n14. Ternary: `condition ? valueIfTrue : valueIfFalse`\n15. Parentheses for grouping: `(a + b) * c`\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\n\nBox(children: (Text | Box)[]) — A box\nText(value: string, tone?: \"a\" | \"b\")\n\n## Built-in Functions\n\nData functions prefixed with `@` to distinguish from components. These are the ONLY functions available — do NOT invent new ones.\nUse @-prefixed built-in functions (@Count, @Sum, @Avg, @Min, @Max, @Round) on Query results — do NOT hardcode computed values.\n\n@Count(array) → number — Returns array length\n@First(array) → element — Returns first element of array\n@Last(array) → element — Returns last element of array\n@Sum(numbers[]) → number — Sum of numeric array\n@Avg(numbers[]) → number — Average of numeric array\n@Min(numbers[]) → number — Minimum value in array\n@Max(numbers[]) → number — Maximum value in array\n@Sort(array, field, direction?) → sorted array — Sort array by field. Direction: \"asc\" (default) or \"desc\"\n@Filter(array, field, operator: \"==\" | \"!=\" | \">\" | \"<\" | \">=\" | \"<=\" | \"contains\", value) → filtered array — Filter array by field value\n@Round(number, decimals?) → number — Round to N decimal places (default 0)\n@Abs(number) → number — Absolute value\n@Floor(number) → number — Round down to nearest integer\n@Ceil(number) → number — Round up to nearest integer\n@Each(array, varName, template) — Evaluate template for each element. varName is the loop variable — use it ONLY inside the template expression (inline). Do NOT create a separate statement for the template.\n\nBuiltins compose — output of one is input to the next:\n`@Count(@Filter(data.rows, \"field\", \"==\", \"val\"))` for KPIs/chart values, `@Round(@Avg(data.rows.score), 1)`, `@Each(data.rows, \"item\", Comp(item.field))` for per-item rendering.\nArray pluck: `data.rows.field` extracts a field from every row → use with @Sum, @Avg, charts, tables.\n\nIMPORTANT @Each rule: The loop variable (e.g. \"item\") is ONLY available inside the @Each template expression. Always inline the template — do NOT extract it to a separate statement.\nCORRECT: `Col(\"Actions\", @Each(rows, \"t\", Button(\"Edit\", Action([@Set($id, t.id)]))))`\nWRONG: `myBtn = Button(\"Edit\", Action([@Set($id, t.id)]))` then `Col(\"Actions\", @Each(rows, \"t\", myBtn))` — t is undefined in myBtn.\n\n## Query — Live Data Fetching\n\nFetch data from available tools. Returns defaults instantly, swaps in real data when it arrives.\n\n```\nmetrics = Query(\"tool_name\", {arg1: value, arg2: $binding}, {defaultField: 0, defaultData: []}, refreshInterval?)\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (may reference $bindings — re-fetches automatically on change)\n- Third arg: default data (rendered immediately before fetch resolves)\n- Fourth arg (optional): refresh interval in seconds (e.g. 30 for auto-refresh every 30s)\n- Use dot access on results: metrics.totalEvents, metrics.data.day (array pluck)\n- Query results must use regular identifiers: `metrics = Query(...)`, NOT `$metrics = Query(...)`\n- Manual refresh: `Button(\"Refresh\", Action([@Run(query1), @Run(query2)]), \"secondary\")` — re-fetches the listed queries\n- Refresh all queries: create Action with @Run for each query\n\n## Mutation — Write Operations\n\nExecute state-changing tool calls (create, update, delete). Unlike Query (auto-fetches on render), Mutation fires only on button click via Action.\n\n```\nresult = Mutation(\"tool_name\", {arg1: $binding, arg2: \"value\"})\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (evaluated with current $binding values at click time)\n- result.status: \"idle\" | \"loading\" | \"success\" | \"error\"\n- result.data: tool response on success\n- result.error: error message on failure\n- Mutation results use regular identifiers: `result = Mutation(...)`, NOT `$result`\n- Show loading state: `result.status == \"loading\" ? TextContent(\"Saving...\") : null`\n\n## Data Workflow\n\nWhen tools are available, follow this workflow:\n1. FIRST: Call the most relevant tool to inspect the real data shape before generating code\n2. Use Query() for READ operations (data that should stay live) — NEVER hardcode tool results as literal arrays or objects\n3. Use Mutation() for WRITE operations (create, update, delete) — triggered by button clicks via Action([@Run(mutationRef)])\n4. Use the real data from step 1 as condensed Query defaults (3-5 rows) so the UI renders immediately\n5. Use @-prefixed builtins (@Count, @Filter, @Sort, @Sum) on Query results for KPIs and aggregations — the runtime evaluates these live on every refresh\n6. Hardcoded arrays are ONLY for static display data (labels, options) where no tool exists\n\nWRONG — you called a tool and got data back, but you inlined the results:\n```\nopenCount = 2\nitem1 = SomeComp(\"first item title\")\nitem2 = SomeComp(\"second item title\")\nlist = SomeList([item1, item2])\nchart = SomeChart([\"A\", \"B\"], [12, 8])\n```\nThis is static — it shows stale data and won't update. Creating item1, item2, item3... manually is ALWAYS wrong when a tool exists.\n\nRIGHT — use Query() for live data, Mutation() for writes, @builtins to derive values:\n```\ndata = Query(\"tool_name\", {}, {rows: []})\nopenCount = @Count(@Filter(data.rows, \"field\", \"==\", \"value\"))\nlist = @Each(data.rows, \"item\", SomeComp(item.title, item.field))\ncreateResult = Mutation(\"create_tool\", {title: $title})\nsubmitBtn = Button(\"Create\", Action([@Run(createResult), @Run(data), @Reset($title)]))\n```\nEverything derives from the Query — when data refreshes, the entire dashboard updates automatically.\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Root(...)` — UI shell appears immediately\n2. $variable declarations — state ready for bindings\n3. Query statements — defaults resolve immediately so components render with data\n4. Component definitions — fill in with data already available\n5. Data values — leaf content last\n\nAlways write the root = Root(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Root(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n3. Every Query result is referenced by at least one component." + } +] diff --git a/packages/swift-lang/Tests/OpenUILangTests/PromptAndLibraryTests.swift b/packages/swift-lang/Tests/OpenUILangTests/PromptAndLibraryTests.swift new file mode 100644 index 0000000000..35544a1519 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/PromptAndLibraryTests.swift @@ -0,0 +1,178 @@ +import Testing + +@testable import OpenUILang + +/// Reads a lang-core `PromptSpec` object from fixture JSON. +func promptSpec(from json: OpenUIValue) -> PromptSpec { + let components = (json["components"].objectValue ?? OpenUIObject()).entries.map { name, value in + ( + name: name, + spec: ComponentPromptSpec( + signature: value["signature"].stringValue ?? "", + description: value["description"].stringValue) + ) + } + let groups = json["componentGroups"].arrayValue?.map { group in + ComponentGroup( + name: group["name"].stringValue ?? "", + components: (group["components"].arrayValue ?? []).compactMap(\.stringValue), + notes: group["notes"].arrayValue?.compactMap(\.stringValue)) + } + let tools: [ToolDescriptor]? = json["tools"].arrayValue?.map { tool in + if case .string(let name) = tool { return .name(name) } + return .spec( + ToolSpec( + name: tool["name"].stringValue ?? "", description: tool["description"].stringValue, + inputSchema: tool["inputSchema"], outputSchema: tool["outputSchema"])) + } + func strings(_ key: String) -> [String]? { json[key].arrayValue?.compactMap(\.stringValue) } + return PromptSpec( + root: json["root"].stringValue, components: components, componentGroups: groups, + options: PromptOptions( + preamble: json["preamble"].stringValue, additionalRules: strings("additionalRules"), + examples: strings("examples"), toolExamples: strings("toolExamples"), tools: tools, + editMode: json["editMode"].boolValue, inlineMode: json["inlineMode"].boolValue, + toolCalls: json["toolCalls"].boolValue, bindings: json["bindings"].boolValue)) +} + +/// The first line where two texts differ, for readable failures. +func firstLineDifference(_ actual: String, _ expected: String) -> String? { + let a = actual.split(separator: "\n", omittingEmptySubsequences: false) + let e = expected.split(separator: "\n", omittingEmptySubsequences: false) + for index in 0.." + let rhs = index < e.count ? String(e[index]) : "" + if lhs != rhs { return "line \(index + 1):\n got: \(lhs)\n expected: \(rhs)" } + } + return nil +} + +@Suite struct PromptConformanceTests { + @Test(arguments: FixtureCase.all("prompts")) + func generatePromptMatchesLangCore(_ fixture: FixtureCase) { + let prompt = generatePrompt(promptSpec(from: fixture.value["spec"])) + let expected = fixture.value["expected"].stringValue! + #expect(prompt == expected, "\(fixture.name): \(firstLineDifference(prompt, expected) ?? "")") + } +} + +/// Swift-defined components must serialize like the Zod-defined originals. +@Suite struct LibraryDSLTests { + static let rules: PropType = .object( + ["required", "email", "url", "numeric"].map { Prop($0, .boolean, .optional) } + + ["min", "max", "minLength", "maxLength"].map { Prop($0, .number, .optional) } + + [Prop("pattern", .string, .optional)]) + + static let components: [ComponentSchema] = [ + ComponentSchema( + "TextContent", + description: + "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".", + props: [ + Prop("text", .string), + Prop( + "size", .enumeration(["small", "default", "large", "small-heavy", "large-heavy"]), + .optional), + ]), + ComponentSchema( + "Input", description: "", + props: [ + Prop("name", .string), Prop("placeholder", .string, .optional), + Prop("type", .enumeration(["text", "email", "password", "number", "url"]), .optional), + Prop("rules", rules, .optional), Prop("value", .string, .optional, binding: true), + ]), + ComponentSchema( + "Button", description: "Clickable button", + props: [ + Prop("label", .string), Prop("action", .actionExpression, .optional), + Prop("variant", .enumeration(["primary", "secondary", "tertiary"]), .optional), + Prop("type", .enumeration(["normal", "destructive"]), .optional), + Prop("size", .enumeration(["extra-small", "small", "medium", "large"]), .optional), + ]), + ComponentSchema( + "Col", description: "Column definition — holds label + data array", + props: [ + Prop("label", .string), Prop("data", .any), + Prop("type", .enumeration(["string", "number", "action"]), .optional), + ]), + ComponentSchema( + "CheckBoxGroup", description: "", + props: [ + Prop("name", .string), Prop("items", .array(.component("CheckBoxItem"))), + Prop("rules", rules, .optional), + Prop("value", .record(.boolean), .optional, binding: true), + ]), + ComponentSchema( + "EntityList", + description: + "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.", + props: [ + Prop("rows", .array(entityRow), .defaulted([])), + Prop("size", .enumeration(["small", "default"]), .defaulted("default")), + Prop("header", entityRow, .optional), Prop("footer", entityRow, .optional), + ]), + ComponentSchema( + "Chips", + description: + "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.", + props: [ + Prop("name", .string), + Prop("type", .enumeration(["single", "multiple"]), .defaulted("multiple")), + Prop("items", .array(.component("ChipItem")), .defaulted([])), + Prop("rules", rules, .optional), + Prop("defaultValue", .union([.string, .array(.string)]), .optional), + ]), + ] + + static let entityRow: PropType = .object([ + Prop("left", .string), Prop("right", .string), + Prop("rightVariant", .enumeration(["text", "number"]), .defaulted("text")), + ]) + + static let chatDefs = Fixtures.schemas["chat"]["schema"]["$defs"] + static let chatSpec = Fixtures.load("chat-spec") + + @Test(arguments: components.map(\.name)) + func schemaMatchesZod(_ name: String) { + let component = Self.components.first { $0.name == name }! + let expected = Self.chatDefs[name] + let diff = firstDifference(normalized(component.jsonSchema), normalized(expected)) + #expect(diff == nil, "\(name): \(diff ?? "")") + // Property order is positional-argument order, so it must match exactly. + #expect( + component.jsonSchema["properties"].objectValue?.keys + == expected["properties"].objectValue?.keys) + } + + @Test(arguments: components.map(\.name)) + func signatureMatchesLangCore(_ name: String) { + let component = Self.components.first { $0.name == name }! + #expect(component.signature == Self.chatSpec["components"][name]["signature"].stringValue) + } + + @Test func libraryWiresBindingsRootAndSchema() { + let library = Library( + components: Self.components.map { ComponentDefinition($0, content: ()) }, root: "TextContent") + #expect(library.isReactiveProp("Input", "value")) + #expect(!library.isReactiveProp("Input", "name")) + #expect( + library.paramMap["Button"]?.map(\.name) == ["label", "action", "variant", "type", "size"]) + #expect(library.toJSONSchema()["required"].arrayValue?.count == Self.components.count) + #expect( + library.toSpec()["components"]["Button"]["signature"].stringValue?.hasPrefix( + "Button(label: string, action?: ActionExpression") == true) + + let result = parse( + "root = TextContent(\"hi\", \"large\")", library.paramMap, rootName: library.rootName) + #expect(result.root?.props == ["text": "hi", "size": "large"]) + } + + @Test func promptIncludesActionAndBindingNotes() { + let library = Library(components: Self.components.map { ComponentDefinition($0, content: ()) }) + let prompt = library.prompt() + #expect( + prompt.contains("Props typed `ActionExpression` accept an Action([@steps...]) expression.")) + #expect(prompt.contains("Props marked `$binding` accept a `$variable` reference")) + #expect(prompt.contains("root = Root(...)")) + } +} From b82598e2038d4b5f05f150cf85ae1bf98af6aea9 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Mon, 5 Oct 2026 06:20:13 +0530 Subject: [PATCH 04/52] feat(swift-lang): add the chat library component schemas ChatComponents defines all 84 openuiChatLibrary components in the Swift DSL, with the same names, prop order, types, defaults, $binding props, descriptions and prompt groups. Array props gain an optional minItems, which the card blocks use. Tests compare every schema with the Zod output, every signature with lang-core's, and the full chat prompt generated from the Swift library with lang-core's, byte for byte. --- .../Sources/OpenUILang/ChatComponents.swift | 1035 +++++++++++++++++ .../Sources/OpenUILang/Library.swift | 11 +- .../OpenUILangTests/ChatComponentsTests.swift | 55 + 3 files changed, 1098 insertions(+), 3 deletions(-) create mode 100644 packages/swift-lang/Sources/OpenUILang/ChatComponents.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift diff --git a/packages/swift-lang/Sources/OpenUILang/ChatComponents.swift b/packages/swift-lang/Sources/OpenUILang/ChatComponents.swift new file mode 100644 index 0000000000..41dd50b59f --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/ChatComponents.swift @@ -0,0 +1,1035 @@ +/// Schemas for the OpenUI chat library. Names, prop order, types and +/// descriptions match `openuiChatLibrary` in @openuidev/react-ui, so a backend +/// that prompts with either library produces responses both can render. +public enum ChatComponents { + /// The structured `rules` object shared by form fields. + public static let formRules: PropType = .object( + ["required", "email", "url", "numeric"].map { Prop($0, .boolean, .optional) } + + ["min", "max", "minLength", "maxLength"].map { Prop($0, .number, .optional) } + + [Prop("pattern", .string, .optional)]) + + public static let card = ComponentSchema( + "Card", + description: + "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.", + props: [ + Prop( + "children", + .array( + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), + .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), + .component("LineChart"), .component("Table"), .component("TagBlock"), + .component("Form"), .component("Buttons"), .component("IconButton"), + .component("Steps"), .component("InlineHeader"), .component("EntityList"), + .component("EditableTable"), .component("SnippetCardBlock"), + .component("OverviewCardBlock"), .component("ContextCardBlock"), + .component("CompositeCardBlock"), .component("VisualCardBlock"), + .component("ListBlock"), .component("FollowUpBlock"), .component("SectionBlock"), + .component("Tabs"), .component("Carousel"), + ]))), + Prop( + "sources", + .array( + .object([ + Prop("url", .string, .optional), Prop("title", .string), Prop("sourceName", .string), + ])), .optional), + ]) + + public static let textContent = ComponentSchema( + "TextContent", + description: + "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".", + props: [ + Prop("text", .string), + Prop( + "size", .enumeration(["small", "default", "large", "small-heavy", "large-heavy"]), .optional + ), + ]) + + public static let markDownRenderer = ComponentSchema( + "MarkDownRenderer", description: "Renders markdown text with optional container variant", + props: [ + Prop("textMarkdown", .string), + Prop("variant", .enumeration(["clear", "card", "sunk"]), .optional), + ]) + + public static let cardHeader = ComponentSchema( + "CardHeader", description: "Header with optional title and subtitle", + props: [Prop("title", .string, .optional), Prop("subtitle", .string, .optional)]) + + public static let callout = ComponentSchema( + "Callout", + description: + "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.", + props: [ + Prop("variant", .enumeration(["info", "warning", "error", "success", "neutral"])), + Prop("title", .string), Prop("description", .string), + Prop("visible", .boolean, .optional, binding: true), + ]) + + public static let textCallout = ComponentSchema( + "TextCallout", description: "Text callout with variant, title, and description", + props: [ + Prop( + "variant", .enumeration(["neutral", "info", "warning", "success", "danger"]), .optional), + Prop("title", .string, .optional), Prop("description", .string, .optional), + ]) + + public static let codeBlock = ComponentSchema( + "CodeBlock", description: "Syntax-highlighted code block", + props: [Prop("language", .string), Prop("codeString", .string)]) + + public static let image = ComponentSchema( + "Image", description: "Image with alt text and optional URL", + props: [Prop("alt", .string), Prop("src", .string, .optional)]) + + public static let imageBlock = ComponentSchema( + "ImageBlock", description: "Image block with loading state", + props: [Prop("src", .string), Prop("alt", .string, .optional)]) + + public static let imageGallery = ComponentSchema( + "ImageGallery", description: "Gallery grid of images with modal preview", + props: [ + Prop( + "images", + .array( + .object([ + Prop("src", .string), Prop("alt", .string, .optional), + Prop("details", .string, .optional), + ]))) + ]) + + public static let separator = ComponentSchema( + "Separator", description: "Visual divider between content sections", + props: [ + Prop("orientation", .enumeration(["horizontal", "vertical"]), .optional), + Prop("decorative", .boolean, .optional), + ]) + + public static let horizontalBarChart = ComponentSchema( + "HorizontalBarChart", + description: "Horizontal bars; prefer when category labels are long or for ranked lists", + props: [ + Prop("labels", .array(.string)), Prop("series", .array(.component("Series"))), + Prop("variant", .enumeration(["grouped", "stacked"]), .optional), + Prop("xLabel", .string, .optional), Prop("yLabel", .string, .optional), + ]) + + public static let series = ComponentSchema( + "Series", description: "One data series", + props: [Prop("category", .string), Prop("values", .array(.number))]) + + public static let radarChart = ComponentSchema( + "RadarChart", + description: + "Spider/web chart; use for comparing multiple variables across one or more entities", + props: [Prop("labels", .array(.string)), Prop("series", .array(.component("Series")))]) + + public static let pieChart = ComponentSchema( + "PieChart", + description: "Circular slices; use plucked arrays: PieChart(data.categories, data.values)", + props: [ + Prop("labels", .array(.string)), Prop("values", .array(.number)), + Prop("variant", .enumeration(["pie", "donut"]), .optional), + Prop("appearance", .enumeration(["circular", "semiCircular"]), .optional), + ]) + + public static let radialChart = ComponentSchema( + "RadialChart", + description: "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)", + props: [Prop("labels", .array(.string)), Prop("values", .array(.number))]) + + public static let singleStackedBarChart = ComponentSchema( + "SingleStackedBarChart", + description: + "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)", + props: [Prop("labels", .array(.string)), Prop("values", .array(.number))]) + + public static let scatterChart = ComponentSchema( + "ScatterChart", + description: "X/Y scatter plot; use for correlations, distributions, and clustering", + props: [ + Prop("datasets", .array(.component("ScatterSeries"))), Prop("xLabel", .string, .optional), + Prop("yLabel", .string, .optional), + ]) + + public static let scatterSeries = ComponentSchema( + "ScatterSeries", description: "Named dataset", + props: [Prop("name", .string), Prop("points", .array(.component("Point")))]) + + public static let point = ComponentSchema( + "Point", description: "Data point with numeric coordinates", + props: [Prop("x", .number), Prop("y", .number), Prop("z", .number, .optional)]) + + public static let areaChart = ComponentSchema( + "AreaChart", + description: "Filled area under lines; use for cumulative totals or volume trends over time", + props: [ + Prop("labels", .array(.string)), Prop("series", .array(.component("Series"))), + Prop("variant", .enumeration(["linear", "natural", "step"]), .optional), + Prop("xLabel", .string, .optional), Prop("yLabel", .string, .optional), + Prop("height", .number, .optional), + ]) + + public static let barChart = ComponentSchema( + "BarChart", + description: + "Vertical bars; use for comparing values across categories with one or more series", + props: [ + Prop("labels", .array(.string)), Prop("series", .array(.component("Series"))), + Prop("variant", .enumeration(["grouped", "stacked"]), .optional), + Prop("xLabel", .string, .optional), Prop("yLabel", .string, .optional), + Prop("height", .number, .optional), + ]) + + public static let lineChart = ComponentSchema( + "LineChart", description: "Lines over categories; use for trends and continuous data over time", + props: [ + Prop("labels", .array(.string)), Prop("series", .array(.component("Series"))), + Prop("variant", .enumeration(["linear", "natural", "step"]), .optional), + Prop("xLabel", .string, .optional), Prop("yLabel", .string, .optional), + Prop("height", .number, .optional), + ]) + + public static let table = ComponentSchema( + "Table", description: "Data table — column-oriented. Each Col holds its own data array.", + props: [Prop("columns", .array(.component("Col")))]) + + public static let col = ComponentSchema( + "Col", description: "Column definition — holds label + data array", + props: [ + Prop("label", .string), Prop("data", .any), + Prop("type", .enumeration(["string", "number", "action"]), .optional), + ]) + + public static let tagBlock = ComponentSchema( + "TagBlock", description: "tags is an array of strings; optional size sm | md | lg", + props: [ + Prop("tags", .array(.string)), Prop("size", .enumeration(["sm", "md", "lg"]), .optional), + ]) + + public static let form = ComponentSchema( + "Form", description: "Form container with fields and explicit action buttons", + props: [ + Prop("name", .string), Prop("buttons", .component("Buttons")), + Prop("fields", .array(.component("FormControl")), .defaulted([])), + ]) + + public static let buttons = ComponentSchema( + "Buttons", + description: "Group of Button components. direction: \"row\" (default) | \"column\".", + props: [ + Prop("buttons", .array(.component("Button"))), + Prop("direction", .enumeration(["row", "column"]), .optional), + ]) + + public static let button = ComponentSchema( + "Button", description: "Clickable button", + props: [ + Prop("label", .string), Prop("action", .actionExpression, .optional), + Prop("variant", .enumeration(["primary", "secondary", "tertiary"]), .optional), + Prop("type", .enumeration(["normal", "destructive"]), .optional), + Prop("size", .enumeration(["extra-small", "small", "medium", "large"]), .optional), + ]) + + public static let formControl = ComponentSchema( + "FormControl", description: "Field with label, input component, and optional hint text", + props: [ + Prop("label", .string), + Prop( + "input", + .union([ + .component("Input"), .component("TextArea"), .component("Select"), + .component("DatePicker"), .component("Slider"), .component("CheckBoxGroup"), + .component("RadioGroup"), .component("Chips"), .component("OptionCards"), + ])), Prop("hint", .string, .optional), + ]) + + public static let input = ComponentSchema( + "Input", description: "", + props: [ + Prop("name", .string), Prop("placeholder", .string, .optional), + Prop("type", .enumeration(["text", "email", "password", "number", "url"]), .optional), + Prop("rules", formRules, .optional), Prop("value", .string, .optional, binding: true), + ]) + + public static let textArea = ComponentSchema( + "TextArea", description: "", + props: [ + Prop("name", .string), Prop("placeholder", .string, .optional), + Prop("rows", .number, .optional), Prop("rules", formRules, .optional), + Prop("value", .string, .optional, binding: true), + ]) + + public static let select = ComponentSchema( + "Select", description: "", + props: [ + Prop("name", .string), Prop("items", .array(.component("SelectItem"))), + Prop("placeholder", .string, .optional), Prop("rules", formRules, .optional), + Prop("value", .string, .optional, binding: true), + Prop("size", .enumeration(["small", "medium", "large"]), .optional), + ]) + + public static let selectItem = ComponentSchema( + "SelectItem", description: "Option for Select", + props: [Prop("value", .string), Prop("label", .string)]) + + public static let datePicker = ComponentSchema( + "DatePicker", description: "", + props: [ + Prop("name", .string), Prop("mode", .enumeration(["single", "range"]), .optional), + Prop("rules", formRules, .optional), Prop("value", .any, .optional, binding: true), + ]) + + public static let slider = ComponentSchema( + "Slider", + description: "Numeric slider input; supports continuous and discrete (stepped) variants", + props: [ + Prop("name", .string), Prop("variant", .enumeration(["continuous", "discrete"])), + Prop("min", .number), Prop("max", .number), Prop("step", .number, .optional), + Prop("defaultValue", .array(.number), .optional), Prop("label", .string, .optional), + Prop("rules", formRules, .optional), Prop("value", .array(.number), .optional, binding: true), + ]) + + public static let checkBoxGroup = ComponentSchema( + "CheckBoxGroup", description: "", + props: [ + Prop("name", .string), Prop("items", .array(.component("CheckBoxItem"))), + Prop("rules", formRules, .optional), + Prop("value", .record(.boolean), .optional, binding: true), + ]) + + public static let checkBoxItem = ComponentSchema( + "CheckBoxItem", description: "", + props: [ + Prop("label", .string), Prop("description", .string), Prop("name", .string), + Prop("defaultChecked", .boolean, .optional), + ]) + + public static let radioGroup = ComponentSchema( + "RadioGroup", description: "", + props: [ + Prop("name", .string), Prop("items", .array(.component("RadioItem"))), + Prop("defaultValue", .string, .optional), Prop("rules", formRules, .optional), + Prop("value", .string, .optional, binding: true), + ]) + + public static let radioItem = ComponentSchema( + "RadioItem", description: "", + props: [Prop("label", .string), Prop("description", .string), Prop("value", .string)]) + + public static let chips = ComponentSchema( + "Chips", + description: + "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.", + props: [ + Prop("name", .string), + Prop("type", .enumeration(["single", "multiple"]), .defaulted("multiple")), + Prop("items", .array(.component("ChipItem")), .defaulted([])), + Prop("rules", formRules, .optional), + Prop("defaultValue", .union([.string, .array(.string)]), .optional), + ]) + + public static let chipItem = ComponentSchema( + "ChipItem", + description: + "A single selectable chip inside a Chips group, with a value, label and optional icon.", + props: [ + Prop("value", .string), Prop("label", .string), Prop("icon", .component("Icon"), .optional), + Prop("disabled", .boolean, .optional), + ]) + + public static let icon = ComponentSchema( + "Icon", + description: + "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.", + props: [Prop("name", .string), Prop("category", .string, .optional)]) + + public static let optionCards = ComponentSchema( + "OptionCards", + description: + "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.", + props: [ + Prop("name", .string), + Prop("type", .enumeration(["single", "multiple"]), .defaulted("single")), + Prop("items", .array(.component("OptionCard")), .defaulted([])), + Prop("rules", formRules, .optional), + Prop("defaultValue", .union([.string, .array(.string)]), .optional), + ]) + + public static let optionCard = ComponentSchema( + "OptionCard", + description: + "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.", + props: [ + Prop("value", .string), Prop("title", .string), Prop("subtitle", .string, .optional), + Prop("topContent", .union([.component("Icon"), .component("Image")]), .optional), + Prop("disabled", .boolean, .optional), + ]) + + public static let iconButton = ComponentSchema( + "IconButton", + description: + "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.", + props: [ + Prop("name", .string), Prop("icon", .component("Icon")), + Prop("action", .actionExpression, .optional), + Prop("variant", .enumeration(["primary", "secondary", "tertiary"]), .optional), + Prop("size", .enumeration(["extra-small", "small", "medium", "large"]), .optional), + Prop("shape", .enumeration(["square", "circle"]), .optional), + ]) + + public static let steps = ComponentSchema( + "Steps", description: "Step-by-step guide", + props: [Prop("items", .array(.component("StepsItem")))]) + + public static let stepsItem = ComponentSchema( + "StepsItem", description: "title and details text for one step", + props: [Prop("title", .string), Prop("details", .string)]) + + public static let inlineHeader = ComponentSchema( + "InlineHeader", + description: + "Compact section heading with an optional one-line description, for use inside cards.", + props: [Prop("heading", .string), Prop("description", .string, .optional)]) + + public static let entityList = ComponentSchema( + "EntityList", + description: + "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.", + props: [ + Prop( + "rows", + .array( + .object([ + Prop("left", .string), Prop("right", .string), + Prop("rightVariant", .enumeration(["text", "number"]), .defaulted("text")), + ])), .defaulted([])), + Prop("size", .enumeration(["small", "default"]), .defaulted("default")), + Prop( + "header", + .object([ + Prop("left", .string), Prop("right", .string), + Prop("rightVariant", .enumeration(["text", "number"]), .defaulted("text")), + ]), .optional), + Prop( + "footer", + .object([ + Prop("left", .string), Prop("right", .string), + Prop("rightVariant", .enumeration(["text", "number"]), .defaulted("text")), + ]), .optional), + ]) + + public static let editableTable = ComponentSchema( + "EditableTable", + description: + "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field", + props: [ + Prop("name", .string, .defaulted("")), + Prop( + "columns", + .array( + .object([ + Prop("type", .enumeration(["text", "number", "date-single", "select", "url"])), + Prop("key", .string, .defaulted("default")), Prop("header", .string, .defaulted("")), + Prop("width", .number, .optional), + Prop( + "options", .array(.object([Prop("value", .string), Prop("label", .string)])), + .optional), + ])), .defaulted([])), + Prop( + "data", + .array( + .object([Prop("id", .string), Prop("values", .array(.union([.string, .number])))])), + .defaulted([])), + ]) + + public static let snippetCardBlock = ComponentSchema( + "SnippetCardBlock", + description: + "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.", + props: [ + Prop("items", .array(.component("SnippetCardItem"), minItems: 2)), + Prop("layout", .enumeration(["grid"]), .defaulted("grid")), + Prop("responsive", .boolean, .defaulted(true)), Prop("action", .actionExpression, .optional), + Prop("gap", .union([.number, .string]), .optional), + ]) + + public static let snippetCardItem = ComponentSchema( + "SnippetCardItem", + description: + "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).", + props: [ + Prop("id", .string, .optional), + Prop("lhs", .union([.component("IconText"), .component("ImageText")])), + Prop("rhs", .union([.component("Text"), .component("BoldText")]), .optional), + ]) + + public static let iconText = ComponentSchema( + "IconText", + description: + "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.", + props: [ + Prop("icon", .component("Icon")), + Prop( + "iconVariant", + .enumeration([ + "neutral", "info", "success", "warning", "danger", "inverted", "filled", "soft", + ]), .defaulted("neutral")), + Prop( + "iconSize", .enumeration(["xs", "s", "m", "l", "xl", "sm", "md", "lg"]), .defaulted("m")), + Prop("title", .string), Prop("subtitle", .string, .optional), + Prop("bold", .boolean, .defaulted(false)), + Prop("layout", .enumeration(["horizontal", "vertical"]), .defaulted("horizontal")), + ]) + + public static let imageText = ComponentSchema( + "ImageText", + description: + "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.", + props: [ + Prop("src", .string), Prop("alt", .string, .optional), Prop("title", .string), + Prop("subtitle", .string, .optional), Prop("bold", .boolean, .defaulted(false)), + Prop("layout", .enumeration(["horizontal", "vertical"]), .defaulted("horizontal")), + Prop("imageSize", .number, .optional), + ]) + + public static let text = ComponentSchema( + "Text", + description: + "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.", + props: [ + Prop("variant", .enumeration(["text", "number"]), .defaulted("text")), Prop("value", .string), + Prop("subtext", .string, .optional), + Prop("subtextVariant", .enumeration(["text", "number", "metric"]), .defaulted("text")), + Prop("size", .enumeration(["xs", "sm", "md", "lg"]), .defaulted("sm")), + ]) + + public static let boldText = ComponentSchema( + "BoldText", + description: + "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.", + props: [ + Prop("variant", .enumeration(["text", "number"]), .defaulted("text")), Prop("value", .string), + Prop("subtext", .string, .optional), + Prop("subtextVariant", .enumeration(["text", "number", "metric"]), .defaulted("text")), + Prop("size", .enumeration(["xs", "sm", "md", "lg"]), .defaulted("sm")), + ]) + + public static let overviewCardBlock = ComponentSchema( + "OverviewCardBlock", + description: + "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.", + props: [ + Prop("items", .array(.component("OverviewCardItem"), minItems: 2)), + Prop("layout", .enumeration(["grid", "carousel"]), .defaulted("grid")), + Prop("responsive", .boolean, .defaulted(true)), Prop("action", .actionExpression, .optional), + Prop("gap", .union([.number, .string]), .optional), + ]) + + public static let overviewCardItem = ComponentSchema( + "OverviewCardItem", + description: + "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.", + props: [ + Prop("id", .string, .optional), + Prop("top", .union([.component("IconText"), .component("ImageText"), .component("Text")])), + Prop("bottom", .component("MetricIndicatorInline"), .optional), + ]) + + public static let metricIndicatorInline = ComponentSchema( + "MetricIndicatorInline", + description: + "Headline metric value with an optional +/- percentage trend and subtext, all on one line.", + props: [ + Prop("value", .string), Prop("subtext", .string, .optional), + Prop( + "trend", + .object([Prop("direction", .enumeration(["up", "down"])), Prop("value", .number)]), + .optional), + ]) + + public static let contextCardBlock = ComponentSchema( + "ContextCardBlock", + description: + "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.", + props: [ + Prop("items", .array(.component("ContextCardItem"), minItems: 2)), + Prop("layout", .enumeration(["grid", "carousel"]), .defaulted("grid")), + Prop("responsive", .boolean, .defaulted(true)), Prop("action", .actionExpression, .optional), + Prop("gap", .union([.number, .string]), .optional), + ]) + + public static let contextCardItem = ComponentSchema( + "ContextCardItem", + description: + "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.", + props: [ + Prop("id", .string, .optional), Prop("title", .union([.string, .component("Tag")])), + Prop("body", .string, .optional), Prop("bgColor", .enumeration(["gray"]), .optional), + Prop("bgImageSrc", .string, .optional), Prop("bgImageAlt", .string, .optional), + ]) + + public static let tag = ComponentSchema( + "Tag", description: "Styled tag/badge with optional Icon and variant", + props: [ + Prop("text", .string), Prop("icon", .component("Icon"), .optional), + Prop("size", .enumeration(["sm", "md", "lg"]), .optional), + Prop( + "variant", .enumeration(["neutral", "info", "success", "warning", "danger"]), .optional), + ]) + + public static let compositeCardBlock = ComponentSchema( + "CompositeCardBlock", + description: + "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.", + props: [ + Prop("items", .array(.component("CompositeCardItem"), minItems: 2)), + Prop("layout", .enumeration(["grid", "carousel"]), .defaulted("grid")), + Prop("responsive", .boolean, .defaulted(true)), Prop("action", .actionExpression, .optional), + Prop("gap", .union([.number, .string]), .optional), + ]) + + public static let compositeCardItem = ComponentSchema( + "CompositeCardItem", + description: + "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.", + props: [ + Prop("id", .string, .optional), + Prop( + "header", + .union([ + .component("IconText"), .component("ImageText"), .component("ImageTextLarge"), + .component("Text"), .component("Image"), + ]), .optional), + Prop( + "body", + .array( + .union([ + .component("Text"), .component("BoldText"), .component("MetricIndicatorInline"), + .component("IconText"), .component("Image"), .component("AreaChart"), + .component("BarChart"), .component("LineChart"), .component("ListBlock"), + .component("TagBlock"), .component("EntityList"), + ])), .defaulted([])), + Prop( + "footer", + .object([ + Prop( + "price", + .union([.component("BoldText"), .component("MetricIndicatorWithStrikethrough")]), + .optional), Prop("button", .component("Button"), .optional), + ]), .optional), + ]) + + public static let imageTextLarge = ComponentSchema( + "ImageTextLarge", + description: + "A full-width banner image above a bold title and optional subtitle. src must be a real image URL.", + props: [ + Prop("src", .string), Prop("alt", .string, .optional), Prop("title", .string), + Prop("subtitle", .string, .optional), Prop("bold", .boolean, .defaulted(false)), + ]) + + public static let listBlock = ComponentSchema( + "ListBlock", + description: + "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.", + props: [ + Prop("items", .array(.component("ListItem"))), + Prop("variant", .enumeration(["number", "image"]), .optional), + Prop("size", .enumeration(["default", "small"]), .optional), + ]) + + public static let listItem = ComponentSchema( + "ListItem", + description: + "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.", + props: [ + Prop("title", .string), Prop("subtitle", .string, .optional), + Prop("image", .object([Prop("src", .string), Prop("alt", .string)]), .optional), + Prop("actionLabel", .string, .optional), Prop("action", .actionExpression, .optional), + ]) + + public static let metricIndicatorWithStrikethrough = ComponentSchema( + "MetricIndicatorWithStrikethrough", + description: + "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.", + props: [ + Prop("value", .string), Prop("subtext", .string, .optional), + Prop("previousValue", .string, .optional), + Prop( + "trend", + .object([Prop("direction", .enumeration(["up", "down"])), Prop("value", .number)]), + .optional), + ]) + + public static let visualCardBlock = ComponentSchema( + "VisualCardBlock", + description: + "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.", + props: [ + Prop("items", .array(.component("VisualCardItem"), minItems: 2)), + Prop("layout", .enumeration(["grid", "carousel"]), .defaulted("grid")), + Prop("responsive", .boolean, .defaulted(true)), Prop("action", .actionExpression, .optional), + Prop("gap", .union([.number, .string]), .optional), + ]) + + public static let visualCardItem = ComponentSchema( + "VisualCardItem", + description: + "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).", + props: [ + Prop("body", .component("BoldText")), Prop("id", .string, .optional), + Prop("bgImageSrc", .string, .optional), Prop("tag", .component("Tag"), .optional), + Prop("bgImageAlt", .string, .optional), + ]) + + public static let followUpBlock = ComponentSchema( + "FollowUpBlock", + description: "List of clickable follow-up suggestions placed at the end of a response", + props: [Prop("items", .array(.component("FollowUpItem")))]) + + public static let followUpItem = ComponentSchema( + "FollowUpItem", + description: "Clickable follow-up suggestion — when clicked, sends text as user message", + props: [Prop("text", .string)]) + + public static let sectionBlock = ComponentSchema( + "SectionBlock", + description: + "Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section.", + props: [ + Prop("sections", .array(.component("SectionItem"))), Prop("isFoldable", .boolean, .optional), + ]) + + public static let sectionItem = ComponentSchema( + "SectionItem", + description: "Section with a label and collapsible content — used inside SectionBlock", + props: [ + Prop("value", .string), Prop("trigger", .string), + Prop( + "content", + .array( + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), + .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), + .component("LineChart"), .component("Table"), .component("TagBlock"), + .component("Form"), .component("Buttons"), .component("IconButton"), + .component("Steps"), .component("InlineHeader"), .component("EntityList"), + .component("EditableTable"), .component("SnippetCardBlock"), + .component("OverviewCardBlock"), .component("ContextCardBlock"), + .component("CompositeCardBlock"), .component("VisualCardBlock"), + .component("ListBlock"), .component("FollowUpBlock"), .component("Tabs"), + .component("Accordion"), + ]))), + ]) + + public static let tabs = ComponentSchema( + "Tabs", description: "Tabbed container", + props: [Prop("items", .array(.component("TabItem")))]) + + public static let tabItem = ComponentSchema( + "TabItem", + description: "value is unique id, trigger is tab label, content is array of components", + props: [ + Prop("value", .string), Prop("trigger", .string), + Prop( + "content", + .array( + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), + .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), + .component("LineChart"), .component("Table"), .component("TagBlock"), + .component("Form"), .component("Buttons"), .component("IconButton"), + .component("Steps"), .component("InlineHeader"), .component("EntityList"), + .component("EditableTable"), .component("SnippetCardBlock"), + .component("OverviewCardBlock"), .component("ContextCardBlock"), + .component("CompositeCardBlock"), .component("VisualCardBlock"), + .component("ListBlock"), .component("FollowUpBlock"), .component("Accordion"), + ]))), + ]) + + public static let accordion = ComponentSchema( + "Accordion", description: "Collapsible sections", + props: [Prop("items", .array(.component("AccordionItem")))]) + + public static let accordionItem = ComponentSchema( + "AccordionItem", description: "value is unique id, trigger is section title", + props: [ + Prop("value", .string), Prop("trigger", .string), + Prop( + "content", + .array( + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), + .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), + .component("LineChart"), .component("Table"), .component("TagBlock"), + .component("Form"), .component("Buttons"), .component("IconButton"), + .component("Steps"), .component("InlineHeader"), .component("EntityList"), + .component("EditableTable"), .component("SnippetCardBlock"), + .component("OverviewCardBlock"), .component("ContextCardBlock"), + .component("CompositeCardBlock"), .component("VisualCardBlock"), + .component("ListBlock"), .component("FollowUpBlock"), + ]))), + ]) + + public static let carousel = ComponentSchema( + "Carousel", description: "Horizontal scrollable carousel", + props: [ + Prop( + "children", + .array( + .array( + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), + .component("SingleStackedBarChart"), .component("ScatterChart"), + .component("AreaChart"), .component("BarChart"), .component("LineChart"), + .component("Table"), .component("TagBlock"), .component("Form"), + .component("Buttons"), .component("IconButton"), .component("Steps"), + .component("InlineHeader"), .component("EntityList"), .component("EditableTable"), + .component("SnippetCardBlock"), .component("OverviewCardBlock"), + .component("ContextCardBlock"), .component("CompositeCardBlock"), + .component("VisualCardBlock"), .component("ListBlock"), .component("FollowUpBlock"), + ])))), Prop("variant", .enumeration(["card", "sunk"]), .optional), + ]) + + public static let slice = ComponentSchema( + "Slice", description: "One slice with label and numeric value", + props: [Prop("category", .string), Prop("value", .number)]) + + public static let label = ComponentSchema( + "Label", description: "Text label", + props: [Prop("text", .string)]) + + public static let switchGroup = ComponentSchema( + "SwitchGroup", description: "Group of switch toggles", + props: [ + Prop("name", .string), Prop("items", .array(.component("SwitchItem"))), + Prop("variant", .enumeration(["clear", "card", "sunk"]), .optional), + Prop("value", .record(.boolean), .optional, binding: true), + ]) + + public static let switchItem = ComponentSchema( + "SwitchItem", description: "Individual switch toggle", + props: [ + Prop("label", .string, .optional), Prop("description", .string, .optional), + Prop("name", .string), Prop("defaultChecked", .boolean, .optional), + ]) + + /// Prompt groups and notes, as in openuiChatLibrary. + public static let groups: [ComponentGroup] = [ + ComponentGroup( + name: "Content", + components: [ + "CardHeader", "TextContent", "MarkDownRenderer", "Callout", "TextCallout", "Image", + "ImageBlock", "ImageGallery", "CodeBlock", "Separator", "InlineHeader", + ], + notes: [ + "- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).", + "- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card.", + ]), + ComponentGroup( + name: "Tables", + components: ["Table", "Col", "EditableTable"], + notes: [ + "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", + "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.", + ]), + ComponentGroup( + name: "Charts (2D)", + components: [ + "BarChart", "LineChart", "AreaChart", "RadarChart", "HorizontalBarChart", "Series", + ]), + ComponentGroup( + name: "Charts (1D)", + components: ["PieChart", "RadialChart", "SingleStackedBarChart", "Slice"]), + ComponentGroup( + name: "Charts (Scatter)", + components: ["ScatterChart", "ScatterSeries", "Point"]), + ComponentGroup( + name: "Forms", + components: [ + "Form", "FormControl", "Label", "Input", "TextArea", "Select", "SelectItem", "DatePicker", + "Slider", "CheckBoxGroup", "CheckBoxItem", "RadioGroup", "RadioItem", "SwitchGroup", + "SwitchItem", "Chips", "ChipItem", "OptionCards", "OptionCard", + ], + notes: [ + "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", + "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", + "- Define EACH FormControl as its own reference — do NOT inline all controls in one array.", + "- NEVER nest Form inside Form.", + "- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).", + "- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }", + "- The renderer shows error messages automatically — do NOT generate error text in the UI", + ]), + ComponentGroup( + name: "Buttons", + components: ["Button", "Buttons", "Icon", "IconButton"], + notes: [ + "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard." + ]), + ComponentGroup( + name: "Lists & Follow-ups", + components: ["ListBlock", "ListItem", "FollowUpBlock", "FollowUpItem"], + notes: [ + "- Use ListBlock with ListItem references for numbered lists.", + "- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.", + "- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.", + "- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.", + "- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })", + ]), + ComponentGroup( + name: "Sections", + components: ["SectionBlock", "SectionItem"], + notes: [ + "- SectionBlock renders collapsible accordion sections that auto-open as they stream.", + "- Each section needs a unique `value` id, a `trigger` label, and a `content` array.", + "- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])", + "- Set isFoldable=false to render sections as flat headers instead of accordion.", + ]), + ComponentGroup( + name: "Layout", + components: [ + "Tabs", "TabItem", "Accordion", "AccordionItem", "Steps", "StepsItem", "Carousel", + ], + notes: [ + "- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.", + "- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])", + "- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.", + "- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.", + "- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs.", + ]), + ComponentGroup( + name: "Data Display", + components: ["TagBlock", "Tag", "EntityList"], + notes: [ + "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not." + ]), + ComponentGroup( + name: "Cards", + components: [ + "SnippetCardBlock", "SnippetCardItem", "OverviewCardBlock", "OverviewCardItem", + "ContextCardBlock", "ContextCardItem", "CompositeCardBlock", "CompositeCardItem", + "VisualCardBlock", "VisualCardItem", "Text", "BoldText", "IconText", "ImageText", + "ImageTextLarge", "MetricIndicatorInline", "MetricIndicatorWithStrikethrough", + ], + notes: [ + "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", + "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", + "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", + "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", + "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", + "- VisualCardItem: image-first card with a BoldText body and optional Tag.", + "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.", + ]), + ] + + /// Every schema, in library order. + public static let all: [ComponentSchema] = [ + card, + textContent, + markDownRenderer, + cardHeader, + callout, + textCallout, + codeBlock, + image, + imageBlock, + imageGallery, + separator, + horizontalBarChart, + series, + radarChart, + pieChart, + radialChart, + singleStackedBarChart, + scatterChart, + scatterSeries, + point, + areaChart, + barChart, + lineChart, + table, + col, + tagBlock, + form, + buttons, + button, + formControl, + input, + textArea, + select, + selectItem, + datePicker, + slider, + checkBoxGroup, + checkBoxItem, + radioGroup, + radioItem, + chips, + chipItem, + icon, + optionCards, + optionCard, + iconButton, + steps, + stepsItem, + inlineHeader, + entityList, + editableTable, + snippetCardBlock, + snippetCardItem, + iconText, + imageText, + text, + boldText, + overviewCardBlock, + overviewCardItem, + metricIndicatorInline, + contextCardBlock, + contextCardItem, + tag, + compositeCardBlock, + compositeCardItem, + imageTextLarge, + listBlock, + listItem, + metricIndicatorWithStrikethrough, + visualCardBlock, + visualCardItem, + followUpBlock, + followUpItem, + sectionBlock, + sectionItem, + tabs, + tabItem, + accordion, + accordionItem, + carousel, + slice, + label, + switchGroup, + switchItem, + ] +} diff --git a/packages/swift-lang/Sources/OpenUILang/Library.swift b/packages/swift-lang/Sources/OpenUILang/Library.swift index f97c0fe550..4d73af2ca9 100644 --- a/packages/swift-lang/Sources/OpenUILang/Library.swift +++ b/packages/swift-lang/Sources/OpenUILang/Library.swift @@ -8,7 +8,8 @@ public indirect enum PropType: Sendable, Equatable { case any case enumeration([String]) case literal(OpenUIValue) - case array(PropType) + /// An array, optionally with a minimum length (`.min(n)` in Zod). + case array(PropType, minItems: Int? = nil) /// A nested object (`z.object`). case object([Prop]) /// `Record`. @@ -131,7 +132,7 @@ private func baseTypeAnnotation(_ type: PropType) -> String { case .union(let options): return options.isEmpty ? "any" : options.map { typeAnnotation($0, binding: false) }.joined(separator: " | ") - case .array(let inner): + case .array(let inner, _): let innerType = typeAnnotation(inner, binding: false) if case .union = inner { return "(\(innerType))[]" } return "\(innerType)[]" @@ -164,7 +165,11 @@ func jsonSchema(_ type: PropType) -> OpenUIValue { return ["type": "string", "enum": .array(values.map { .string($0) })] case .literal(let value): return ["type": .string(value.jsTypeof), "const": value] - case .array(let inner): return ["type": "array", "items": jsonSchema(inner)] + case .array(let inner, let minItems): + var schema: OpenUIObject = ["type": "array"] + if let minItems { schema["minItems"] = .number(Double(minItems)) } + schema["items"] = jsonSchema(inner) + return .object(schema) case .object(let props): return objectSchema(props) case .record(let value): return [ diff --git a/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift b/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift new file mode 100644 index 0000000000..19c61d2230 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift @@ -0,0 +1,55 @@ +import Testing + +@testable import OpenUILang + +/// The chat component schemas must match openuiChatLibrary's Zod schemas, so +/// one backend prompt drives both the web and native renderers. +@Suite struct ChatComponentsTests { + static let tsDefs = Fixtures.schemas["chat"]["schema"]["$defs"] + static let tsSpec = Fixtures.load("chat-spec") + + @Test(arguments: ChatComponents.all.map(\.name)) + func matchesOpenUIChatLibrary(_ name: String) { + let schema = ChatComponents.all.first { $0.name == name }! + let expected = Self.tsDefs[name] + let diff = firstDifference(normalized(schema.jsonSchema), normalized(expected)) + #expect(diff == nil, "\(name): \(diff ?? "")") + // Property order is positional-argument order, so it must match exactly. + #expect( + schema.jsonSchema["properties"].objectValue?.keys == expected["properties"].objectValue?.keys) + #expect(schema.signature == Self.tsSpec["components"][name]["signature"].stringValue) + } + + @Test func coversEveryComponentInLibraryOrder() { + #expect(ChatComponents.all.map(\.name) == Self.tsDefs.objectValue?.keys) + } + + @Test func bindingsMatchReactiveProps() { + let reactive = Fixtures.schemas["chat"]["reactive"].objectValue ?? OpenUIObject() + for schema in ChatComponents.all { + let expected = (reactive[schema.name]?.arrayValue ?? []).compactMap(\.stringValue) + #expect(schema.props.filter(\.isBinding).map(\.name) == expected, "\(schema.name)") + } + } + + @Test func groupsMatchOpenUIChatLibrary() { + let expected = (Self.tsSpec["componentGroups"].arrayValue ?? []).map { group in + ComponentGroup( + name: group["name"].stringValue ?? "", + components: (group["components"].arrayValue ?? []).compactMap(\.stringValue), + notes: group["notes"].arrayValue?.compactMap(\.stringValue)) + } + #expect(ChatComponents.groups == expected) + } + + @Test func chatLibraryPromptMatchesLangCore() { + // The full chat prompt (no options) is one of the prompt fixtures. + let fixture = FixtureCase.all("prompts").first { $0.name == "chat-default" }! + let library = Library( + components: ChatComponents.all.map { ComponentDefinition($0, content: ()) }, root: "Card", + componentGroups: ChatComponents.groups) + let prompt = library.prompt() + let expected = fixture.value["expected"].stringValue! + #expect(prompt == expected, "\(firstLineDifference(prompt, expected) ?? "")") + } +} From f40d62c53724bbaedc51ebb72509ee810dc3b845 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Mon, 5 Oct 2026 06:20:13 +0530 Subject: [PATCH 05/52] feat(swift-lang): render OpenUI responses with SwiftUI Adds OpenUISwiftUI: - OpenUIRenderer, a view that renders a (streaming) response with a component library, backed by an observable OpenUIContext around OpenUIRuntime; node identity follows statement names so inputs keep focus and local state while the response re-renders - OpenUIChatLibrary, native SwiftUI views for every openuiChatLibrary component: content, Swift Charts (bar, line, area, horizontal bar, pie, radial, stacked, scatter, plus a drawn radar chart), tables and the editable table, forms with validation, chips and option cards, buttons, lists, tabs, accordions, sections, carousels and the card blocks - lucide icon names mapped to SF Symbols with react-ui's category fallbacks - card block clicks that merge item context into the action like react-ui's withItemContext Tests cover library completeness, card actions, icon mapping, node identity, context updates and an offscreen end-to-end render of every chat library example. --- packages/swift-lang/Package.swift | 5 + .../swift-lang/Scripts/generate-fixtures.mjs | 92 ++- .../OpenUISwiftUI/ComponentProps.swift | 55 ++ .../Components/CardComponents.swift | 579 ++++++++++++++++++ .../Components/ChartComponents.swift | 363 +++++++++++ .../Components/ContentComponents.swift | 368 +++++++++++ .../Components/FormComponents.swift | 517 ++++++++++++++++ .../Components/IconComponents.swift | 440 +++++++++++++ .../Components/LayoutComponents.swift | 369 +++++++++++ .../Components/SelectionComponents.swift | 267 ++++++++ .../OpenUISwiftUI/FormValidation.swift | 103 ++++ .../OpenUISwiftUI/OpenUIChatLibrary.swift | 116 ++++ .../Sources/OpenUISwiftUI/OpenUIContext.swift | 120 ++++ .../Sources/OpenUISwiftUI/OpenUINode.swift | 85 +++ .../OpenUISwiftUI/OpenUIRenderer.swift | 69 +++ .../Sources/OpenUISwiftUI/Support.swift | 190 ++++++ .../Sources/OpenUISwiftUI/Theme.swift | 79 +++ .../Fixtures/chat-examples.json | 22 + .../OpenUISwiftUITests/RendererTests.swift | 179 ++++++ 19 files changed, 3996 insertions(+), 22 deletions(-) create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/ComponentProps.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/FormValidation.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/OpenUIChatLibrary.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/OpenUINode.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Support.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift create mode 100644 packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chat-examples.json create mode 100644 packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift diff --git a/packages/swift-lang/Package.swift b/packages/swift-lang/Package.swift index 49444d1584..0001f98c0d 100644 --- a/packages/swift-lang/Package.swift +++ b/packages/swift-lang/Package.swift @@ -16,5 +16,10 @@ let package = Package( dependencies: ["OpenUILang"], resources: [.copy("Fixtures")] ), + .testTarget( + name: "OpenUISwiftUITests", + dependencies: ["OpenUISwiftUI"], + resources: [.copy("Fixtures")] + ), ] ) diff --git a/packages/swift-lang/Scripts/generate-fixtures.mjs b/packages/swift-lang/Scripts/generate-fixtures.mjs index 9e3f8fb235..d23555e010 100644 --- a/packages/swift-lang/Scripts/generate-fixtures.mjs +++ b/packages/swift-lang/Scripts/generate-fixtures.mjs @@ -33,7 +33,13 @@ const testSchema = { properties: { children: { type: "array", - items: { anyOf: [{ $ref: "#/$defs/Text" }, { $ref: "#/$defs/Button" }, { $ref: "#/$defs/Chart" }] }, + items: { + anyOf: [ + { $ref: "#/$defs/Text" }, + { $ref: "#/$defs/Button" }, + { $ref: "#/$defs/Chart" }, + ], + }, }, title: { type: "string" }, }, @@ -139,7 +145,7 @@ const edgeCases = [ t("required-default-fills", 'root = Card([x])\nx = Tagged(1, true, "x", null)'), t("unknown-component", 'root = Card([Mystery("a"), Text("b")])'), t("excess-args", 'root = Card([Text("a", "m", "extra", 4)])'), - t("type-mismatch-scalar", 'root = Card([Text(42)], 7)'), + t("type-mismatch-scalar", "root = Card([Text(42)], 7)"), t("enum-mismatch", 'root = Card([Text("a", "xl"), Button("b", null, "tertiary")])'), t("enum-partial-deferred", 'root = Card([Text("a", "x'), t("integer-boolean-const", 'root = Card([x])\nx = Tagged(1.5, "yes", "y", "loud")'), @@ -149,7 +155,7 @@ const edgeCases = [ ), t("array-items-pruned", 'root = Card([Chart(["a", 2, "c"], [1, "x", 3])])'), t("element-in-data-slot", 'root = Card([Chart([Text("a")], [1])])'), - t("unresolved-and-orphaned", "root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")"), + t("unresolved-and-orphaned", 'root = Card([a, missing])\na = Text("x")\nlonely = Text("y")'), t("cycle", "root = Card([a])\na = Card([b])\nb = Card([a])"), t("self-reference", "root = Card([root])"), t("no-root-first-component", 'x = 1\nmain = Card([Text("a")])\nother = Card([])'), @@ -217,8 +223,8 @@ const edgeCases = [ '$o = {b: 1, 2: "two", a: 3, 1: "one", "10": 10}\nroot = Card([Text("x")])', ), t("missing-commas", 'root = Card([Text("a") Text("b"), Text("c"),])'), - t("lowercase-builtin-name", 'root = Card([Text(@first([1]))])'), - t("unknown-tokens", "root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo"), + t("lowercase-builtin-name", "root = Card([Text(@first([1]))])"), + t("unknown-tokens", 'root = Card([Text("a")]) ; ~ ^\n$ = 3\n= 4\nfoo'), t( "combining-characters", 'root = Card([Text("e\\u0301 cafe\\u0301"), Text("한국어"), Text("ok")])', @@ -326,19 +332,17 @@ const evalCases = [ "ternary-components", '$on = true\nroot = Card([$on ? Text("on", "l") : Button("off"), $on ? null : Text("hidden")])', ), - e( - "ternary-components-off", - '$on = true\nroot = Card([$on ? Text("on", "l") : Button("off")])', - { state: { $on: false } }, - ), - e("state-override", '$count = 1\nroot = Card([Text("count " + $count)])', { state: { $count: 41 } }), + e("ternary-components-off", '$on = true\nroot = Card([$on ? Text("on", "l") : Button("off")])', { + state: { $on: false }, + }), + e("state-override", '$count = 1\nroot = Card([Text("count " + $count)])', { + state: { $count: 41 }, + }), e("reactive-binding", '$v = "hi"\nroot = Card([Input("name", $v), Input("plain", "x")])'), e("reactive-assign", '$v = ""\nroot = Card([Input("name", $v = $value)])'), - e( - "query-results", - edgeCases.find((c) => c.name === "query-mutation").input, - { queryResults: { users: { rows: [{ id: 1 }, { id: 2 }] }, save: { status: "idle" } } }, - ), + e("query-results", edgeCases.find((c) => c.name === "query-mutation").input, { + queryResults: { users: { rows: [{ id: 1 }, { id: 2 }] }, save: { status: "idle" } }, + }), e( "each-actions", '$items = [{id: 1, t: "a"}, {id: 2, t: "b"}]\n$sel = 0\nroot = Card(@Each($items, it, Button(it.t, Action([@Set($sel, it.id), @ToAssistant("Pick " + it.t)]))))', @@ -359,7 +363,10 @@ const tools = [ description: "Open support tickets", inputSchema: { type: "object", - properties: { status: { type: "string", enum: ["open", "closed"] }, limit: { type: "number" } }, + properties: { + status: { type: "string", enum: ["open", "closed"] }, + limit: { type: "number" }, + }, required: ["status"], }, outputSchema: { @@ -376,18 +383,34 @@ const tools = [ const smallSpec = { components: { Box: { signature: "Box(children: (Text | Box)[])", description: "A box" }, - Text: { signature: "Text(value: string, tone?: \"a\" | \"b\")" }, + Text: { signature: 'Text(value: string, tone?: "a" | "b")' }, }, }; // A slice of the chat library that still exercises ActionExpression, // $binding, groups and ungrouped components, to keep variant fixtures small. -const sliceNames = ["Card", "TextContent", "Button", "Buttons", "Form", "FormControl", "Input", "Select", "SelectItem", "Table", "Col"]; +const sliceNames = [ + "Card", + "TextContent", + "Button", + "Buttons", + "Form", + "FormControl", + "Input", + "Select", + "SelectItem", + "Table", + "Col", +]; const sliceSpec = { root: chatSpec.root, components: Object.fromEntries(sliceNames.map((n) => [n, chatSpec.components[n]])), componentGroups: [ - { name: "Forms", components: ["Form", "FormControl", "Input", "Select", "SelectItem"], notes: ["- Forms note"] }, + { + name: "Forms", + components: ["Form", "FormControl", "Input", "Select", "SelectItem"], + notes: ["- Forms note"], + }, { name: "Buttons", components: ["Button", "Buttons", "Missing"] }, ], }; @@ -396,11 +419,25 @@ const promptCases = [ { name: "chat-default", spec: chatSpec }, { name: "chat-options", spec: { ...chatSpec, ...ui.openuiChatPromptOptions } }, { name: "slice-bindings", spec: { ...sliceSpec, bindings: true } }, - { name: "slice-tools", spec: { ...sliceSpec, tools, toolExamples: ['x = Query("list_tickets", {status: "open"}, {rows: []})'] } }, + { + name: "slice-tools", + spec: { + ...sliceSpec, + tools, + toolExamples: ['x = Query("list_tickets", {status: "open"}, {rows: []})'], + }, + }, { name: "slice-tools-no-bindings", spec: { ...sliceSpec, tools, bindings: false } }, { name: "slice-modes", - spec: { ...sliceSpec, editMode: true, inlineMode: true, preamble: "Custom preamble.", additionalRules: ["Be brief"], examples: ["a = 1"] }, + spec: { + ...sliceSpec, + editMode: true, + inlineMode: true, + preamble: "Custom preamble.", + additionalRules: ["Be brief"], + examples: ["a = 1"], + }, }, { name: "slice-no-groups", spec: { ...sliceSpec, componentGroups: undefined } }, { name: "small-no-root", spec: smallSpec }, @@ -420,6 +457,17 @@ write("streaming.json", streamingCases, 0); write("stream-set.json", setCases); write("evaluation.json", evalFixtures); write("prompts.json", promptCases); + +// The chat examples, for the SwiftUI renderer's end-to-end render tests. +mkdirSync(join(here, "..", "Tests", "OpenUISwiftUITests", "Fixtures"), { recursive: true }); +writeFileSync( + join(here, "..", "Tests", "OpenUISwiftUITests", "Fixtures", "chat-examples.json"), + JSON.stringify( + chatExamples.map(({ name, input }) => ({ name, input })), + null, + 1, + ) + "\n", +); write("chat-spec.json", chatComponentSpecs); console.log( diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/ComponentProps.swift b/packages/swift-lang/Sources/OpenUISwiftUI/ComponentProps.swift new file mode 100644 index 0000000000..bb4b4220cb --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/ComponentProps.swift @@ -0,0 +1,55 @@ +import OpenUILang +import SwiftUI + +/// A component's evaluated props, with typed accessors that tolerate the +/// missing and partial values a streaming response produces. +public struct ComponentProps { + public let typeName: String + public let statementId: String? + public let values: OpenUIObject + + public init(_ element: ElementNode) { + typeName = element.typeName + statementId = element.statementId + values = element.props + } + + public subscript(key: String) -> OpenUIValue { values[key] ?? .undefined } + + /// The prop as a string, if it is one. + public func string(_ key: String) -> String? { self[key].stringValue } + + /// The prop as display text: strings as-is, numbers and booleans formatted + /// like JavaScript, anything else empty. + public func text(_ key: String) -> String { displayText(self[key]) } + + public func number(_ key: String) -> Double? { self[key].numberValue } + + public func bool(_ key: String) -> Bool? { self[key].boolValue } + + public func array(_ key: String) -> [OpenUIValue] { self[key].arrayValue ?? [] } + + /// Child elements in the prop (arrays skip non-element items). + public func elements(_ key: String) -> [ElementNode] { + switch self[key] { + case .element(let element): return [element] + case .array(let items): return items.compactMap(\.elementValue) + default: return [] + } + } + + /// Child element props, for components that read sub-components' data + /// (e.g. a chart reading its `Series`). + public func children(_ key: String) -> [ComponentProps] { + elements(key).map(ComponentProps.init) + } +} + +/// Text for scalar values: strings as-is, numbers and booleans like JavaScript. +public func displayText(_ value: OpenUIValue) -> String { + switch value { + case .string(let string): return string + case .number, .bool: return value.jsString + default: return "" + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift new file mode 100644 index 0000000000..5287972681 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift @@ -0,0 +1,579 @@ +import OpenUILang +import SwiftUI + +// MARK: - Click context + +/// Merges an item's click context into a card block's `action`, like +/// react-ui's `withItemContext`: +/// - no action: continue the conversation with the item context as params; +/// - an `Action([...])` plan: append "Selected item: {…}" to its +/// `@ToAssistant` contexts (the only channel the host receives for them); +/// - a legacy `{ type, params, url, context }` object: merge into params. +func withItemContext(_ action: OpenUIValue, _ itemContext: OpenUIObject) -> OpenUIValue { + let context = OpenUIObject(itemContext.entries.filter { $0.value != .undefined }) + switch action { + case .undefined, .null: + return ["type": .string(BuiltinActionType.continueConversation), "params": .object(context)] + case .actionPlan(let plan): + if context.isEmpty { return action } + let suffix = "Selected item: \(JSON.stringify(.object(context)))" + return .actionPlan( + ActionPlan( + steps: plan.steps.map { step in + guard case .continueConversation(let message, let existing) = step else { return step } + let merged = existing.map { $0.isEmpty ? suffix : "\($0)\n\(suffix)" } ?? suffix + return .continueConversation(message: message, context: merged) + })) + default: + var params = action["params"].objectValue ?? OpenUIObject() + if action["url"] != .undefined { params["url"] = action["url"] } + if action["context"].isTruthy { params["context"] = action["context"] } + for (key, value) in context { params[key] = value } + let type = + action["type"].isNullish ? .string(BuiltinActionType.continueConversation) : action["type"] + return ["type": type, "params": .object(params)] + } +} + +/// A string prop of a child element (`getStringProp` in react-ui). +private func childString(_ node: OpenUIValue, _ key: String) -> String? { + node.elementValue?.props[key]?.stringValue +} + +// MARK: - Blocks + +/// Lays out card items in a two-column grid or a horizontal carousel and makes +/// them clickable when the block has an action (and the response isn't streaming). +private struct CardBlockLayout: View { + let props: ComponentProps + let click: (Int, ComponentProps) -> (label: String, context: OpenUIObject) + @ViewBuilder let item: (ComponentProps) -> Item + @Environment(OpenUIContext.self) private var context + @Environment(\.openUIFormName) private var form + @Environment(\.openUITheme) private var theme + + var body: some View { + let items = props.children("items") + let gap = props.number("gap").map { CGFloat($0) } ?? theme.spacing + let clickable = props["action"].isTruthy && !context.isStreaming + if props.string("layout") == "carousel" { + ScrollView(.horizontal, showsIndicators: false) { + HStack(alignment: .top, spacing: gap) { + ForEach(Array(items.enumerated()), id: \.offset) { index, entry in + card(index, entry, clickable: clickable).frame(width: 240) + } + } + .padding(.vertical, 2) + } + } else { + let columns = props.bool("responsive") == false ? 2 : min(2, max(items.count, 1)) + LazyVGrid( + columns: Array( + repeating: GridItem(.flexible(), spacing: gap, alignment: .top), count: columns), + alignment: .leading, spacing: gap + ) { + ForEach(Array(items.enumerated()), id: \.offset) { index, entry in + card(index, entry, clickable: clickable) + } + } + } + } + + @ViewBuilder + private func card(_ index: Int, _ entry: ComponentProps, clickable: Bool) -> some View { + let content = item(entry).frame(maxWidth: .infinity, alignment: .topLeading) + if clickable { + Button { + let (label, itemContext) = click(index, entry) + context.triggerAction( + label, form: form, action: withItemContext(props["action"], itemContext)) + } label: { + content.contentShape(Rectangle()) + } + .buttonStyle(.plain) + } else { + content + } + } +} + +/// The bordered tile every card item sits on. +private struct CardTile: View { + var padding: CGFloat = 12 + var tint: Color? = nil + @ViewBuilder let content: Content + @Environment(\.openUITheme) private var theme + + var body: some View { + VStack(alignment: .leading, spacing: 8) { content } + .padding(padding) + .frame(maxWidth: .infinity, alignment: .topLeading) + .background(tint ?? theme.surface, in: RoundedRectangle(cornerRadius: theme.cornerRadius)) + .overlay(RoundedRectangle(cornerRadius: theme.cornerRadius).strokeBorder(theme.border)) + } +} + +struct SnippetCardBlockView: View { + let props: ComponentProps + var body: some View { + CardBlockLayout(props: props) { index, item in + let title = childString(item["lhs"], "title") + return ( + title ?? item.string("id") ?? "Snippet card \(index + 1)", + [ + "itemIndex": .number(Double(index)), "itemId": item["id"], + "itemTitle": title.map(OpenUIValue.string) ?? .undefined, + "itemSubtitle": childString(item["lhs"], "subtitle").map(OpenUIValue.string) + ?? .undefined, + "itemValue": childString(item["rhs"], "value").map(OpenUIValue.string) ?? .undefined, + ] + ) + } item: { + SnippetCard(item: $0) + } + } +} + +struct SnippetCardItemView: View { + let props: ComponentProps + var body: some View { SnippetCard(item: props) } +} + +private struct SnippetCard: View { + let item: ComponentProps + + var body: some View { + let value = compactValue + CardTile { + // Side by side when it fits; otherwise the value moves under the label + // rather than squeezing it into mid-word breaks. + ViewThatFits(in: .horizontal) { + HStack(alignment: .center, spacing: 8) { + OpenUINode(item["lhs"]).fixedSize(horizontal: true, vertical: false) + Spacer(minLength: 8) + OpenUINode(value).fixedSize() + } + VStack(alignment: .leading, spacing: 8) { + OpenUINode(item["lhs"]) + OpenUINode(value) + } + } + } + } + + /// The value sits small on the right, as in react-ui. + private var compactValue: OpenUIValue { + guard var rhs = item["rhs"].elementValue else { return item["rhs"] } + rhs.props["size"] = "xs" + return .element(rhs) + } +} + +struct OverviewCardBlockView: View { + let props: ComponentProps + var body: some View { + CardBlockLayout(props: props) { index, item in + let title = childString(item["top"], "title") ?? childString(item["top"], "value") + let subtitle = childString(item["top"], "subtitle") ?? childString(item["top"], "subtext") + return ( + title ?? item.string("id") ?? "Overview card \(index + 1)", + [ + "itemIndex": .number(Double(index)), "itemId": item["id"], + "itemTitle": title.map(OpenUIValue.string) ?? .undefined, + "itemSubtitle": subtitle.map(OpenUIValue.string) ?? .undefined, + "itemMetricValue": item["bottom"].elementValue?.props["value"] ?? .undefined, + ] + ) + } item: { + OverviewCard(item: $0) + } + } +} + +struct OverviewCardItemView: View { + let props: ComponentProps + var body: some View { OverviewCard(item: props) } +} + +private struct OverviewCard: View { + let item: ComponentProps + var body: some View { + CardTile { + OpenUINode(item["top"]) + OpenUINode(item["bottom"]) + } + } +} + +struct ContextCardBlockView: View { + let props: ComponentProps + var body: some View { + CardBlockLayout(props: props) { index, item in + let title = contextTitle(item) + return ( + title.isEmpty ? (item.string("id") ?? "Context card \(index + 1)") : title, + [ + "itemIndex": .number(Double(index)), "itemId": item["id"], "itemTitle": .string(title), + "itemBody": item["body"], "itemBgColor": item["bgColor"], + "itemBgImageSrc": item["bgImageSrc"], "itemBgImageAlt": item["bgImageAlt"], + ] + ) + } item: { + ContextCard(item: $0) + } + } +} + +struct ContextCardItemView: View { + let props: ComponentProps + var body: some View { ContextCard(item: props) } +} + +/// A context card's title text: the string, or its Tag's text. +private func contextTitle(_ item: ComponentProps) -> String { + switch item["title"] { + case .string(let title): return title + case .element(let tag): return tag.props["text"]?.stringValue ?? "" + default: return "" + } +} + +/// A compact tinted card, or a photo card with a scrim when it has a +/// background image. +private struct ContextCard: View { + let item: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + let image = item.string("bgImageSrc").flatMap { $0.isEmpty ? nil : $0 } + VStack(alignment: .leading, spacing: 6) { + if case .element = item["title"] { + OpenUINode(item["title"]) + } else { + Text(item.text("title")).font(.subheadline).opacity(0.75) + } + if let body = item.string("body"), !body.isEmpty { + Text(body).font(.headline) + } + } + .padding(12) + .frame(maxWidth: .infinity, minHeight: image == nil ? nil : 130, alignment: .bottomLeading) + .foregroundStyle(image == nil ? Color.primary : Color.white) + .background { + if let image { + RemoteImage(src: image, alt: item.text("bgImageAlt")) + .overlay( + LinearGradient( + colors: [.black.opacity(0.1), .black.opacity(0.7)], startPoint: .top, + endPoint: .bottom)) + } else { + item.string("bgColor") == "gray" ? theme.sunkSurface : theme.surface + } + } + .clipShape(RoundedRectangle(cornerRadius: theme.cornerRadius)) + .overlay(RoundedRectangle(cornerRadius: theme.cornerRadius).strokeBorder(theme.border)) + } +} + +struct CompositeCardBlockView: View { + let props: ComponentProps + var body: some View { + CardBlockLayout(props: props) { index, item in + let header = item["header"].elementValue?.props ?? OpenUIObject() + func pick(_ keys: String...) -> String? { + keys.lazy.compactMap { header[$0]?.stringValue }.first + } + let title = pick("title", "value") + let alt = pick("alt") + let footer = item["footer"] + let label = [title, alt, item.string("id")].compactMap { $0 }.first { !$0.isEmpty } + return ( + label ?? "Composite card \(index + 1)", + [ + "itemIndex": .number(Double(index)), "itemId": item["id"], + "itemHeaderTitle": title.map(OpenUIValue.string) ?? .undefined, + "itemHeaderSubtitle": pick("subtitle", "subtext").map(OpenUIValue.string) ?? .undefined, + "itemHeaderAlt": alt.map(OpenUIValue.string) ?? .undefined, + "itemBodyCount": .number(Double(item.array("body").count)), + "itemFooterPrice": footer["price"].elementValue?.props["value"] ?? .undefined, + "itemFooterButtonLabel": footer["button"].elementValue?.props["label"] ?? .undefined, + ] + ) + } item: { + CompositeCard(item: $0) + } + } +} + +struct CompositeCardItemView: View { + let props: ComponentProps + var body: some View { CompositeCard(item: props) } +} + +private struct CompositeCard: View { + let item: ComponentProps + var body: some View { + CardTile { + OpenUINode(item["header"]) + OpenUINodes(item.array("body"), spacing: 8) + let footer = item["footer"] + if !footer["price"].isNullish || !footer["button"].isNullish { + HStack(alignment: .center) { + OpenUINode(footer["price"]) + Spacer(minLength: 8) + OpenUINode(footer["button"]) + } + } + } + } +} + +struct VisualCardBlockView: View { + let props: ComponentProps + var body: some View { + CardBlockLayout(props: props) { index, item in + let bodyValue = item["body"].elementValue?.props["value"]?.stringValue + let tagText = item["tag"].elementValue?.props["text"]?.stringValue + let label = [bodyValue, tagText, item.string("id")].compactMap { $0 }.first { !$0.isEmpty } + return ( + label ?? "Visual card \(index + 1)", + [ + "itemIndex": .number(Double(index)), "itemId": item["id"], + "itemTag": tagText.map(OpenUIValue.string) ?? .undefined, + "itemBody": bodyValue.map(OpenUIValue.string) ?? .undefined, + "itemBodySubtext": item["body"].elementValue?.props["subtext"] ?? .undefined, + "itemBgImageSrc": item["bgImageSrc"], "itemBgImageAlt": item["bgImageAlt"], + ] + ) + } item: { + VisualCard(item: $0) + } + } +} + +struct VisualCardItemView: View { + let props: ComponentProps + var body: some View { VisualCard(item: props) } +} + +/// A photo-first card: full-bleed image, tag on top, bold text panel below. +private struct VisualCard: View { + let item: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + RemoteImage(src: item.string("bgImageSrc"), alt: item.text("bgImageAlt")) + .frame(height: 140) + .clipped() + .overlay(alignment: .topLeading) { + OpenUINode(item["tag"]) + .environment(\.openUITagOnImage, true) + .padding(8) + } + OpenUINode(item["body"]).padding(12) + } + .background(theme.surface) + .clipShape(RoundedRectangle(cornerRadius: theme.cornerRadius)) + .overlay(RoundedRectangle(cornerRadius: theme.cornerRadius).strokeBorder(theme.border)) + } +} + +// MARK: - Building blocks + +/// `Text` / `BoldText`: a value line with optional subtext. `variant "number"` +/// uses tabular digits; `subtextVariant "metric"` colors a leading +/- green/red. +struct TextLineView: View { + let props: ComponentProps + let bold: Bool + + var body: some View { + VStack(alignment: .leading, spacing: 2) { + Text(props.text("value")) + .font(font.weight(bold ? .semibold : .regular)) + .monospacedDigit(props.string("variant") == "number") + if let subtext = props.string("subtext"), !subtext.isEmpty { + Text(subtext) + .font(.caption) + .monospacedDigit(props.string("subtextVariant") != "text") + .foregroundStyle(subtextColor(subtext)) + } + } + } + + private var font: Font { + switch props.string("size") { + case "xs": return .footnote + case "sm": return .subheadline + case "lg": return .title2 + default: return .body + } + } + + private func subtextColor(_ subtext: String) -> Color { + guard props.string("subtextVariant") == "metric" else { return .secondary } + if subtext.hasPrefix("+") { return .green } + if subtext.hasPrefix("-") || subtext.hasPrefix("−") { return .red } + return .secondary + } +} + +extension View { + @ViewBuilder + fileprivate func monospacedDigit(_ enabled: Bool) -> some View { + if enabled { monospacedDigit() } else { self } + } +} + +struct IconTextView: View { + let props: ComponentProps + + var body: some View { + let vertical = props.string("layout") == "vertical" + let layout = + vertical + ? AnyLayout(VStackLayout(alignment: .leading, spacing: 8)) + : AnyLayout(HStackLayout(spacing: 10)) + layout { + IconBadge( + symbol: iconSymbol(props["icon"]) + ?? LucideSymbols.systemName(for: "circle-dot", category: nil), + variant: props.string("iconVariant"), size: props.string("iconSize")) + TitleStack(props: props) + } + } +} + +/// An icon on a tinted rounded square. +private struct IconBadge: View { + let symbol: String + let variant: String? + let size: String? + @Environment(\.openUITheme) private var theme + + var body: some View { + let side: CGFloat = + switch size { + case "xs": 20 + case "s", "sm": 26 + case "l", "lg": 40 + case "xl": 48 + default: 32 + } + let (foreground, background) = colors + Image(systemName: symbol) + .font(.system(size: side * 0.5)) + .foregroundStyle(foreground) + .frame(width: side, height: side) + .background(background, in: RoundedRectangle(cornerRadius: theme.smallCornerRadius)) + } + + private var colors: (Color, Color) { + switch variant { + case "info", "success", "warning", "danger": + let color = statusColor(variant) + return (color, color.opacity(0.14)) + case "inverted": return (Color(white: 0.98), Color.primary) + case "filled": return (.white, .accentColor) + case "soft": return (.accentColor, Color.accentColor.opacity(0.14)) + default: return (.primary, theme.sunkSurface) + } + } +} + +/// Title (bold when asked) with an optional subtitle. +private struct TitleStack: View { + let props: ComponentProps + var body: some View { + VStack(alignment: .leading, spacing: 2) { + Text(props.text("title")).fontWeight(props.bool("bold") == true ? .semibold : .medium) + if let subtitle = props.string("subtitle"), !subtitle.isEmpty { + Text(subtitle).font(.caption).foregroundStyle(.secondary) + } + } + } +} + +struct ImageTextView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + let size = CGFloat(props.number("imageSize") ?? 40) + let vertical = props.string("layout") == "vertical" + let layout = + vertical + ? AnyLayout(VStackLayout(alignment: .leading, spacing: 8)) + : AnyLayout(HStackLayout(spacing: 10)) + layout { + RemoteImage(src: props.string("src"), alt: props.text("alt")) + .frame(width: size, height: size) + TitleStack(props: props) + } + } +} + +struct ImageTextLargeView: View { + let props: ComponentProps + + var body: some View { + VStack(alignment: .leading, spacing: 8) { + RemoteImage(src: props.string("src"), alt: props.text("alt")) + .frame(height: 160) + .clipped() + TitleStack(props: props) + } + } +} + +struct MetricIndicatorInlineView: View { + let props: ComponentProps + + var body: some View { + VStack(alignment: .leading, spacing: 2) { + HStack(alignment: .firstTextBaseline, spacing: 6) { + Text(props.text("value")).font(.headline.monospacedDigit()) + TrendLabel(trend: props["trend"]) + } + if let subtext = props.string("subtext"), !subtext.isEmpty { + Text(subtext).font(.caption).foregroundStyle(.secondary) + } + } + } +} + +struct MetricIndicatorWithStrikethroughView: View { + let props: ComponentProps + + var body: some View { + VStack(alignment: .leading, spacing: 2) { + HStack(alignment: .firstTextBaseline, spacing: 6) { + Text(props.text("value")).font(.title3.weight(.semibold).monospacedDigit()) + if let previous = props.string("previousValue"), !previous.isEmpty { + Text(previous).font(.subheadline).strikethrough().foregroundStyle(.secondary) + } + TrendLabel(trend: props["trend"]) + } + if let subtext = props.string("subtext"), !subtext.isEmpty { + Text(subtext).font(.caption).foregroundStyle(.secondary) + } + } + } +} + +/// `{ direction, value }` as an arrow and percentage, green up, red down. +private struct TrendLabel: View { + let trend: OpenUIValue + + var body: some View { + if let value = trend["value"].numberValue { + let up = trend["direction"].stringValue == "up" + HStack(spacing: 2) { + Image(systemName: up ? "arrow.up.right" : "arrow.down.right") + Text("\(jsNumberToString(value))%") + } + .font(.caption.weight(.medium).monospacedDigit()) + .foregroundStyle(up ? .green : .red) + } + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift new file mode 100644 index 0000000000..bc94be63aa --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift @@ -0,0 +1,363 @@ +import Charts +import OpenUILang +import SwiftUI + +/// One value of one series at one category label. +private struct SeriesPoint: Identifiable { + let id: Int + let label: String + let series: String + let value: Double +} + +/// Flattens `labels` + `[Series(category, values)]` into chart points. +/// Missing values (still streaming) are skipped. +private func seriesPoints(_ props: ComponentProps) -> [SeriesPoint] { + let labels = props.array("labels").map(displayText) + var points: [SeriesPoint] = [] + for series in props.children("series") { + let name = series.text("category") + for (index, value) in series.array("values").enumerated() where index < labels.count { + guard let number = value.numberValue, number.isFinite else { continue } + points.append( + SeriesPoint(id: points.count, label: labels[index], series: name, value: number)) + } + } + return points +} + +/// Category labels in their given order (charts otherwise sort them). +private func labelOrder(_ props: ComponentProps) -> [String] { + var seen: Set = [] + return props.array("labels").map(displayText).filter { seen.insert($0).inserted } +} + +private func interpolation(_ variant: String?) -> InterpolationMethod { + switch variant { + case "natural": return .monotone + case "step": return .stepCenter + default: return .linear + } +} + +private struct ChartFrame: View { + let props: ComponentProps + let content: Content + @Environment(\.openUITheme) private var theme + + init(_ props: ComponentProps, @ViewBuilder content: () -> Content) { + self.props = props + self.content = content() + } + + var body: some View { + content + .frame(height: props.number("height").map { CGFloat($0) } ?? theme.chartHeight) + .chartLegend(position: .bottom, alignment: .leading) + } +} + +struct BarChartView: View { + let props: ComponentProps + + var body: some View { + let points = seriesPoints(props) + let stacked = props.string("variant") == "stacked" + ChartFrame(props) { + Chart(points) { point in + if stacked { + BarMark(x: .value("Label", point.label), y: .value("Value", point.value)) + .foregroundStyle(by: .value("Series", point.series)) + } else { + BarMark(x: .value("Label", point.label), y: .value("Value", point.value)) + .foregroundStyle(by: .value("Series", point.series)) + .position(by: .value("Series", point.series)) + } + } + .chartXScale(domain: labelOrder(props)) + .chartXAxisLabel(props.text("xLabel")) + .chartYAxisLabel(props.text("yLabel")) + } + } +} + +struct HorizontalBarChartView: View { + let props: ComponentProps + + var body: some View { + let points = seriesPoints(props) + let stacked = props.string("variant") == "stacked" + let labels = labelOrder(props) + ChartFrame(props) { + Chart(points) { point in + if stacked { + BarMark( + x: .value("Value", point.value), y: .value("Label", point.label), height: .ratio(0.7) + ) + .foregroundStyle(by: .value("Series", point.series)) + } else { + BarMark( + x: .value("Value", point.value), y: .value("Label", point.label), height: .ratio(0.7) + ) + .foregroundStyle(by: .value("Series", point.series)) + .position(by: .value("Series", point.series)) + } + } + .chartYScale(domain: labels) + .chartYAxis { + AxisMarks(preset: .aligned, position: .leading) { _ in + AxisValueLabel(horizontalSpacing: 8) + } + } + .frame(minHeight: CGFloat(labels.count) * 28) + .chartXAxisLabel(props.text("xLabel")) + .chartYAxisLabel(props.text("yLabel")) + } + } +} + +struct LineChartView: View { + let props: ComponentProps + + var body: some View { + let method = interpolation(props.string("variant")) + ChartFrame(props) { + Chart(seriesPoints(props)) { point in + LineMark(x: .value("Label", point.label), y: .value("Value", point.value)) + .foregroundStyle(by: .value("Series", point.series)) + .interpolationMethod(method) + PointMark(x: .value("Label", point.label), y: .value("Value", point.value)) + .foregroundStyle(by: .value("Series", point.series)) + .symbolSize(18) + } + .chartXScale(domain: labelOrder(props)) + .chartXAxisLabel(props.text("xLabel")) + .chartYAxisLabel(props.text("yLabel")) + } + } +} + +struct AreaChartView: View { + let props: ComponentProps + + var body: some View { + let method = interpolation(props.string("variant")) + ChartFrame(props) { + Chart(seriesPoints(props)) { point in + AreaMark( + x: .value("Label", point.label), y: .value("Value", point.value), + stacking: .unstacked + ) + .foregroundStyle(by: .value("Series", point.series)) + .opacity(0.25) + .interpolationMethod(method) + LineMark(x: .value("Label", point.label), y: .value("Value", point.value)) + .foregroundStyle(by: .value("Series", point.series)) + .interpolationMethod(method) + } + .chartXScale(domain: labelOrder(props)) + .chartXAxisLabel(props.text("xLabel")) + .chartYAxisLabel(props.text("yLabel")) + } + } +} + +/// One labelled value of a 1D chart. +private struct Slice: Identifiable { + let id: Int + let label: String + let value: Double +} + +private func slices(_ props: ComponentProps) -> [Slice] { + let labels = props.array("labels").map(displayText) + return props.array("values").enumerated().compactMap { index, value in + guard index < labels.count, let number = value.numberValue, number.isFinite, number >= 0 else { + return nil + } + return Slice(id: index, label: labels[index], value: number) + } +} + +struct PieChartView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + let data = slices(props) + let donut = props.string("variant") == "donut" + let semi = props.string("appearance") == "semiCircular" + let total = data.reduce(0) { $0 + $1.value } + Chart { + ForEach(data) { slice in + SectorMark( + angle: .value("Value", slice.value), innerRadius: .ratio(donut ? 0.6 : 0), + angularInset: 1 + ) + .foregroundStyle(by: .value("Label", slice.label)) + } + if semi, total > 0 { + // A transparent half that keeps the visible slices on the top half. + SectorMark(angle: .value("Value", total), innerRadius: .ratio(donut ? 0.6 : 0)) + .foregroundStyle(.clear) + } + } + .chartLegend(position: .bottom, alignment: .leading) + .rotationEffect(semi ? .degrees(-90) : .zero) + .frame(height: theme.chartHeight) + } +} + +struct RadialChartView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + let data = slices(props) + let maximum = max(data.map(\.value).max() ?? 1, 1) + HStack(spacing: theme.spacing) { + ZStack { + ForEach(data) { slice in + let inset = CGFloat(slice.id) * 14 + Circle() + .stroke(.secondary.opacity(0.15), lineWidth: 10) + .padding(inset) + Circle() + .trim(from: 0, to: slice.value / maximum * 0.75) + .stroke(Self.color(slice.id), style: StrokeStyle(lineWidth: 10, lineCap: .round)) + .rotationEffect(.degrees(-90)) + .padding(inset) + } + } + .frame(width: theme.chartHeight * 0.8, height: theme.chartHeight * 0.8) + VStack(alignment: .leading, spacing: 4) { + ForEach(data) { slice in + HStack(spacing: 6) { + Circle().fill(Self.color(slice.id)).frame(width: 8, height: 8) + Text(slice.label).font(.caption) + Text(jsNumberToString(slice.value)).font(.caption.monospacedDigit()) + .foregroundStyle(.secondary) + } + } + } + } + } + + static let palette: [Color] = [.blue, .green, .orange, .purple, .pink, .teal, .yellow, .red] + static func color(_ index: Int) -> Color { palette[index % palette.count] } +} + +struct SingleStackedBarChartView: View { + let props: ComponentProps + + var body: some View { + Chart(slices(props)) { slice in + BarMark(x: .value("Value", slice.value), y: .value("Total", "")) + .foregroundStyle(by: .value("Label", slice.label)) + } + .chartYAxis(.hidden) + .chartLegend(position: .bottom, alignment: .leading) + .frame(height: 80) + } +} + +struct ScatterChartView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + private struct Dot: Identifiable { + let id: Int + let series: String + let x: Double + let y: Double + let z: Double? + } + + var body: some View { + var dots: [Dot] = [] + for dataset in props.children("datasets") { + for point in dataset.children("points") { + guard let x = point.number("x"), let y = point.number("y") else { continue } + dots.append( + Dot(id: dots.count, series: dataset.text("name"), x: x, y: y, z: point.number("z"))) + } + } + return Chart(dots) { dot in + PointMark(x: .value(props.text("xLabel"), dot.x), y: .value(props.text("yLabel"), dot.y)) + .foregroundStyle(by: .value("Series", dot.series)) + .symbolSize(dot.z.map { max(20, min($0, 400)) } ?? 40) + } + .chartXAxisLabel(props.text("xLabel")) + .chartYAxisLabel(props.text("yLabel")) + .chartLegend(position: .bottom, alignment: .leading) + .frame(height: theme.chartHeight) + } +} + +/// Spider chart: one axis per label, one filled polygon per series. Swift +/// Charts has no radar mark, so it is drawn directly. +struct RadarChartView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + let labels = props.array("labels").map(displayText) + let series = props.children("series").map { series in + (name: series.text("category"), values: series.array("values").map { $0.numberValue ?? 0 }) + } + let maximum = max(series.flatMap(\.values).max() ?? 1, 1) + VStack(alignment: .leading, spacing: 8) { + Canvas { context, size in + guard labels.count >= 3 else { return } + let center = CGPoint(x: size.width / 2, y: size.height / 2) + let radius = min(size.width, size.height) / 2 - 28 + func point(_ index: Int, _ fraction: Double) -> CGPoint { + let angle = -Double.pi / 2 + 2 * Double.pi * Double(index) / Double(labels.count) + return CGPoint( + x: center.x + CGFloat(cos(angle) * fraction) * radius, + y: center.y + CGFloat(sin(angle) * fraction) * radius) + } + func polygon(_ fractions: [Double]) -> Path { + Path { path in + for (index, fraction) in fractions.enumerated() { + index == 0 + ? path.move(to: point(index, fraction)) : path.addLine(to: point(index, fraction)) + } + path.closeSubpath() + } + } + for ring in 1...4 { + context.stroke( + polygon(Array(repeating: Double(ring) / 4, count: labels.count)), + with: .color(.secondary.opacity(0.25))) + } + for index in labels.indices { + var axis = Path() + axis.move(to: center) + axis.addLine(to: point(index, 1)) + context.stroke(axis, with: .color(.secondary.opacity(0.25))) + context.draw( + Text(labels[index]).font(.caption2).foregroundStyle(.secondary), at: point(index, 1.16)) + } + for (index, entry) in series.enumerated() { + let fractions = labels.indices.map { + $0 < entry.values.count ? entry.values[$0] / maximum : 0 + } + let shape = polygon(fractions) + let color = RadialChartView.color(index) + context.fill(shape, with: .color(color.opacity(0.18))) + context.stroke(shape, with: .color(color), lineWidth: 2) + } + } + .frame(height: theme.chartHeight + 40) + FlowLayout(spacing: 12) { + ForEach(Array(series.enumerated()), id: \.offset) { index, entry in + HStack(spacing: 6) { + Circle().fill(RadialChartView.color(index)).frame(width: 8, height: 8) + Text(entry.name).font(.caption).foregroundStyle(.secondary) + } + } + } + } + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift new file mode 100644 index 0000000000..231d21ee91 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift @@ -0,0 +1,368 @@ +import OpenUILang +import SwiftUI + +// MARK: - Card + +struct CardView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + VStack(alignment: .leading, spacing: theme.spacing) { + OpenUINodes(props.array("children")) + let sources = props.array("sources") + if !sources.isEmpty { + SourcesStrip(sources: sources) + } + } + .frame(maxWidth: .infinity, alignment: .leading) + .surface("card") + } +} + +/// Numbered references cited inline as [1], [2] in the card's text. +private struct SourcesStrip: View { + let sources: [OpenUIValue] + @Environment(\.openUITheme) private var theme + + var body: some View { + VStack(alignment: .leading, spacing: theme.compactSpacing) { + Divider() + Text("Sources").font(.caption.weight(.semibold)).foregroundStyle(.secondary) + ForEach(Array(sources.enumerated()), id: \.offset) { index, source in + let title = displayText(source["title"]) + let name = displayText(source["sourceName"]) + HStack(alignment: .firstTextBaseline, spacing: 6) { + Text("[\(index + 1)]").font(.caption.monospacedDigit()).foregroundStyle(.secondary) + if let url = source["url"].stringValue.flatMap(URL.init(string:)) { + Link(title, destination: url).font(.caption) + } else { + Text(title).font(.caption) + } + if !name.isEmpty { Text(name).font(.caption).foregroundStyle(.secondary) } + } + } + } + } +} + +struct CardHeaderView: View { + let props: ComponentProps + + var body: some View { + VStack(alignment: .leading, spacing: 2) { + if let title = props.string("title"), !title.isEmpty { + Text(title).font(.title3.weight(.semibold)) + } + if let subtitle = props.string("subtitle"), !subtitle.isEmpty { + Text(subtitle).font(.subheadline).foregroundStyle(.secondary) + } + } + } +} + +// MARK: - Text + +struct TextContentView: View { + let props: ComponentProps + + var body: some View { + InlineMarkdown(props.text("text")) + .font(font) + .frame(maxWidth: .infinity, alignment: .leading) + } + + private var font: Font { + switch props.string("size") { + case "small": return .footnote + case "large": return .title3 + case "small-heavy": return .footnote.weight(.semibold) + case "large-heavy": return .title3.weight(.semibold) + default: return .body + } + } +} + +struct MarkDownRendererView: View { + let props: ComponentProps + + var body: some View { + MarkdownBlocks(props.text("textMarkdown")) + .frame(maxWidth: .infinity, alignment: .leading) + .surface(props.string("variant") ?? "clear") + } +} + +struct InlineHeaderView: View { + let props: ComponentProps + + var body: some View { + VStack(alignment: .leading, spacing: 2) { + Text(props.text("heading")).font(.headline) + if let description = props.string("description"), !description.isEmpty { + Text(description).font(.subheadline).foregroundStyle(.secondary) + } + } + } +} + +// MARK: - Callouts + +struct CalloutView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + + var body: some View { + let field = context.stateField(name: "visible", binding: props["visible"], form: nil) + let visible = field.isReactive ? (field.value == true || field.value == "true") : true + if visible { + Banner( + variant: props.string("variant"), title: props.text("title"), + description: props.text("description") + ) + .task(id: field.isReactive && !context.isStreaming) { + // A $visible binding auto-dismisses the callout after 3 seconds. + guard field.isReactive, !context.isStreaming else { return } + try? await Task.sleep(nanoseconds: 3_000_000_000) + if !Task.isCancelled { field.setValue(false) } + } + } + } +} + +struct TextCalloutView: View { + let props: ComponentProps + + var body: some View { + Banner( + variant: props.string("variant") ?? "neutral", title: props.text("title"), + description: props.text("description")) + } +} + +private struct Banner: View { + let variant: String? + let title: String + let description: String + @Environment(\.openUITheme) private var theme + + var body: some View { + let color = statusColor(variant) + HStack(alignment: .top, spacing: 10) { + Image(systemName: symbol).foregroundStyle(color) + VStack(alignment: .leading, spacing: 2) { + if !title.isEmpty { Text(title).font(.subheadline.weight(.semibold)) } + if !description.isEmpty { InlineMarkdown(description).font(.subheadline) } + } + Spacer(minLength: 0) + } + .padding(12) + .background(color.opacity(0.1), in: RoundedRectangle(cornerRadius: theme.smallCornerRadius)) + .overlay( + RoundedRectangle(cornerRadius: theme.smallCornerRadius).strokeBorder(color.opacity(0.35))) + } + + private var symbol: String { + switch variant { + case "warning": return "exclamationmark.triangle.fill" + case "error", "danger": return "xmark.octagon.fill" + case "success": return "checkmark.circle.fill" + case "info": return "info.circle.fill" + default: return "text.bubble.fill" + } + } +} + +// MARK: - Code + +struct CodeBlockView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + VStack(alignment: .leading, spacing: 6) { + if let language = props.string("language"), !language.isEmpty { + Text(language).font(.caption.weight(.medium)).foregroundStyle(.secondary) + } + ScrollView(.horizontal, showsIndicators: false) { + Text(props.text("codeString")) + .font(.system(.callout, design: .monospaced)) + .textSelection(.enabled) + .fixedSize(horizontal: true, vertical: false) + } + } + .padding(12) + .frame(maxWidth: .infinity, alignment: .leading) + .background(theme.sunkSurface, in: RoundedRectangle(cornerRadius: theme.smallCornerRadius)) + } +} + +// MARK: - Images + +struct ImageView: View { + let props: ComponentProps + + var body: some View { + RemoteImage(src: props.string("src"), alt: props.text("alt"), fit: true) + } +} + +struct ImageBlockView: View { + let props: ComponentProps + + var body: some View { + RemoteImage(src: props.string("src"), alt: props.text("alt"), fit: true) + } +} + +struct ImageGalleryView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + ScrollView(.horizontal, showsIndicators: false) { + HStack(alignment: .top, spacing: theme.spacing) { + ForEach(Array(props.array("images").enumerated()), id: \.offset) { _, image in + VStack(alignment: .leading, spacing: 4) { + RemoteImage(src: image["src"].stringValue, alt: displayText(image["alt"])) + .frame(width: 220, height: 150) + .clipped() + let details = displayText(image["details"]) + if !details.isEmpty { + Text(details).font(.caption).foregroundStyle(.secondary).frame( + width: 220, alignment: .leading) + } + } + } + } + } + } +} + +/// An image loaded from a URL, with the alt text as its accessibility label +/// and a placeholder while loading (or when the URL is missing). +/// +/// `fit` keeps the image's aspect ratio at the available width (content +/// images). Otherwise the image fills whatever frame the caller gives it and +/// never affects layout, so a large photo can't widen a card or grid column. +struct RemoteImage: View { + let src: String? + let alt: String + var fit = false + @Environment(\.openUITheme) private var theme + + var body: some View { + Group { + if fit { + AsyncImage(url: url) { phase in + if let image = phase.image { + image.resizable().scaledToFit() + } else { + placeholder(phase).frame(height: 160) + } + } + .frame(maxWidth: .infinity) + } else { + Color.clear + .overlay { + AsyncImage(url: url) { phase in + if let image = phase.image { + image.resizable().scaledToFill() + } else { + placeholder(phase) + } + } + } + .clipped() + } + } + .clipShape(RoundedRectangle(cornerRadius: theme.smallCornerRadius)) + .accessibilityLabel(alt) + } + + private var url: URL? { src.flatMap(URL.init(string:)) } + + private func placeholder(_ phase: AsyncImagePhase) -> some View { + ZStack { + theme.sunkSurface + Image(systemName: phase.error == nil ? "photo" : "photo.badge.exclamationmark") + .font(.title2).foregroundStyle(.secondary) + } + } +} + +// MARK: - Separator, tags and key/value rows + +struct SeparatorView: View { + let props: ComponentProps + + var body: some View { + if props.string("orientation") == "vertical" { + Divider().frame(maxHeight: 24) + } else { + Divider() + } + } +} + +struct TagBlockView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + FlowLayout(spacing: theme.compactSpacing) { + ForEach(Array(props.array("tags").enumerated()), id: \.offset) { _, tag in + Text(displayText(tag)) + .font(font) + .padding(.horizontal, 8) + .padding(.vertical, 3) + .background(theme.sunkSurface, in: Capsule()) + .overlay(Capsule().strokeBorder(theme.border)) + } + } + } + + private var font: Font { + switch props.string("size") { + case "sm": return .caption2 + case "lg": return .callout + default: return .caption + } + } +} + +struct EntityListView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + let small = props.string("size") == "small" + VStack(spacing: 0) { + if !small, let header = props["header"].objectValue { + row(.object(header), emphasis: true) + Divider() + } + ForEach(Array(props.array("rows").enumerated()), id: \.offset) { index, item in + if index > 0 { Divider().opacity(0.5) } + row(item, emphasis: false) + } + if !small, let footer = props["footer"].objectValue { + Divider() + row(.object(footer), emphasis: true) + } + } + .font(small ? .footnote : .callout) + } + + private func row(_ item: OpenUIValue, emphasis: Bool) -> some View { + HStack { + Text(displayText(item["left"])).foregroundStyle(emphasis ? .primary : .secondary) + Spacer(minLength: theme.spacing) + Text(displayText(item["right"])) + .monospacedDigit() + .multilineTextAlignment(.trailing) + } + .fontWeight(emphasis ? .semibold : .regular) + .padding(.vertical, 6) + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift new file mode 100644 index 0000000000..d70feda066 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift @@ -0,0 +1,517 @@ +import OpenUILang +import SwiftUI + +// MARK: - Form + +struct FormView: View { + let props: ComponentProps + @State private var validation = FormValidation() + @Environment(\.openUITheme) private var theme + + var body: some View { + VStack(alignment: .leading, spacing: theme.spacing + 4) { + OpenUINode(props["fields"]) + OpenUINode(props["buttons"]) + } + .environment(\.openUIFormName, props.string("name")) + .environment(validation) + } +} + +struct FormControlView: View { + let props: ComponentProps + @Environment(FormValidation.self) private var validation: FormValidation? + + var body: some View { + let fieldName = props.children("input").first?.string("name") + VStack(alignment: .leading, spacing: 6) { + Text(props.text("label")).font(.subheadline.weight(.medium)) + OpenUINode(props["input"]) + if let fieldName, let error = validation?.error(for: fieldName) { + Text(error).font(.caption).foregroundStyle(.red) + } else if let hint = props.string("hint"), !hint.isEmpty { + Text(hint).font(.caption).foregroundStyle(.secondary) + } + } + } +} + +struct LabelView: View { + let props: ComponentProps + + var body: some View { + Text(props.text("text")).font(.subheadline.weight(.medium)) + } +} + +/// The field a form component reads and writes, plus its validation rules. +private struct FieldContext { + let field: StateField + let rules: [ParsedRule] + let form: String? + + @MainActor + init(_ props: ComponentProps, context: OpenUIContext, form: String?) { + self.field = context.stateField(name: props.text("name"), binding: props["value"], form: form) + self.rules = parseStructuredRules(props["rules"]) + self.form = form + } +} + +// MARK: - Text input + +struct InputView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + @Environment(\.openUIFormName) private var form + @Environment(FormValidation.self) private var validation: FormValidation? + + var body: some View { + let state = FieldContext(props, context: context, form: form) + let text = Binding( + get: { displayText(state.field.value) }, + set: { newValue in + state.field.setValue(.string(newValue)) + if !state.rules.isEmpty { validation?.clearError(state.field.name) } + }) + Group { + if props.string("type") == "password" { + SecureField(props.text("placeholder"), text: text) + } else { + TextField(props.text("placeholder"), text: text) + #if os(iOS) + .keyboardType(keyboard) + .textInputAutocapitalization(autocapitalization) + #endif + } + } + .textFieldStyle(.roundedBorder) + .disabled(context.isStreaming) + .onSubmit { + if !state.rules.isEmpty { + validation?.validateField(state.field.name, value: state.field.value, rules: state.rules) + } + } + .formField(state.field.name, rules: state.rules, value: state.field.value) + } + + #if os(iOS) + private var keyboard: UIKeyboardType { + switch props.string("type") { + case "email": return .emailAddress + case "url": return .URL + case "number": return .decimalPad + default: return .default + } + } + + private var autocapitalization: TextInputAutocapitalization { + ["email", "url"].contains(props.string("type") ?? "") ? .never : .sentences + } + #endif +} + +struct TextAreaView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + @Environment(\.openUIFormName) private var form + @Environment(FormValidation.self) private var validation: FormValidation? + + var body: some View { + let state = FieldContext(props, context: context, form: form) + let rows = max(Int(props.number("rows") ?? 3), 1) + TextField( + props.text("placeholder"), + text: Binding( + get: { displayText(state.field.value) }, + set: { newValue in + state.field.setValue(.string(newValue)) + if !state.rules.isEmpty { validation?.clearError(state.field.name) } + }), + axis: .vertical + ) + .lineLimit(rows...max(rows, 12)) + .textFieldStyle(.roundedBorder) + .disabled(context.isStreaming) + .formField(state.field.name, rules: state.rules, value: state.field.value) + } +} + +// MARK: - Choices + +struct SelectView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + @Environment(\.openUIFormName) private var form + @Environment(FormValidation.self) private var validation: FormValidation? + + var body: some View { + let state = FieldContext(props, context: context, form: form) + let items = props.children("items") + Picker( + props.text("placeholder"), + selection: Binding( + get: { displayText(state.field.value) }, + set: { newValue in + state.field.setValue(.string(newValue)) + if !state.rules.isEmpty { + validation?.validateField( + state.field.name, value: .string(newValue), rules: state.rules) + } + }) + ) { + Text(props.string("placeholder") ?? "Select…").tag("") + ForEach(Array(items.enumerated()), id: \.offset) { _, item in + Text(item.text("label")).tag(item.text("value")) + } + } + .pickerStyle(.menu) + .labelsHidden() + .disabled(context.isStreaming) + .formField(state.field.name, rules: state.rules, value: state.field.value) + } +} + +struct SelectItemView: View { + let props: ComponentProps + + var body: some View { + Text(props.text("label")) + } +} + +struct RadioGroupView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + @Environment(\.openUIFormName) private var form + @Environment(FormValidation.self) private var validation: FormValidation? + + var body: some View { + let state = FieldContext(props, context: context, form: form) + let selected = + state.field.value.isNullish ? props.text("defaultValue") : displayText(state.field.value) + VStack(alignment: .leading, spacing: 8) { + ForEach(Array(props.children("items").enumerated()), id: \.offset) { _, item in + let value = item.text("value") + Button { + state.field.setValue(.string(value)) + if !state.rules.isEmpty { + validation?.validateField(state.field.name, value: .string(value), rules: state.rules) + } + } label: { + OptionRow( + symbol: value == selected ? "largecircle.fill.circle" : "circle", + label: item.text("label"), description: item.text("description")) + } + .buttonStyle(.plain) + } + } + .disabled(context.isStreaming) + .formField(state.field.name, rules: state.rules, value: state.field.value) + } +} + +struct RadioItemView: View { + let props: ComponentProps + + var body: some View { + OptionRow(symbol: "circle", label: props.text("label"), description: props.text("description")) + } +} + +/// A group of named booleans stored as one `{ name: Bool }` record, shared by +/// check boxes and switches. Unset items fall back to `defaultChecked`. +private struct BooleanGroup: View { + let props: ComponentProps + let style: Style + @Environment(OpenUIContext.self) private var context + @Environment(\.openUIFormName) private var form + @Environment(FormValidation.self) private var validation: FormValidation? + + enum Style { case checkbox, toggle } + + var body: some View { + let state = FieldContext(props, context: context, form: form) + let items = props.children("items") + let stored = state.field.value.objectValue ?? OpenUIObject() + let aggregate = OpenUIObject( + items.map { item in + let name = item.text("name") + let value = stored[name]?.boolValue ?? item.bool("defaultChecked") ?? false + return (name, OpenUIValue.bool(value)) + }) + VStack(alignment: .leading, spacing: 8) { + ForEach(Array(items.enumerated()), id: \.offset) { _, item in + let name = item.text("name") + let isOn = aggregate[name]?.boolValue ?? false + let toggle = { + var next = aggregate + next[name] = .bool(!isOn) + state.field.setValue(.object(next)) + if !state.rules.isEmpty { + validation?.validateField(state.field.name, value: .object(next), rules: state.rules) + } + } + switch style { + case .checkbox: + Button(action: toggle) { + OptionRow( + symbol: isOn ? "checkmark.square.fill" : "square", label: item.text("label"), + description: item.text("description")) + } + .buttonStyle(.plain) + case .toggle: + Toggle(isOn: Binding(get: { isOn }, set: { _ in toggle() })) { + VStack(alignment: .leading, spacing: 2) { + Text(item.text("label")) + if let description = item.string("description"), !description.isEmpty { + Text(description).font(.caption).foregroundStyle(.secondary) + } + } + } + .toggleStyle(.switch) + } + } + } + .disabled(context.isStreaming) + .formField(state.field.name, rules: state.rules, value: state.field.value) + } +} + +struct CheckBoxGroupView: View { + let props: ComponentProps + var body: some View { BooleanGroup(props: props, style: .checkbox) } +} + +struct SwitchGroupView: View { + let props: ComponentProps + var body: some View { + BooleanGroup(props: props, style: .toggle).surface(props.string("variant") ?? "clear") + } +} + +struct CheckBoxItemView: View { + let props: ComponentProps + var body: some View { + OptionRow( + symbol: props.bool("defaultChecked") == true ? "checkmark.square.fill" : "square", + label: props.text("label"), description: props.text("description")) + } +} + +struct SwitchItemView: View { + let props: ComponentProps + var body: some View { + Toggle(props.text("label"), isOn: .constant(props.bool("defaultChecked") ?? false)) + .toggleStyle(.switch) + .disabled(true) + } +} + +/// A selectable row: indicator symbol, label and optional description. +private struct OptionRow: View { + let symbol: String + let label: String + let description: String + + var body: some View { + HStack(alignment: .firstTextBaseline, spacing: 8) { + Image(systemName: symbol).foregroundStyle(Color.accentColor) + VStack(alignment: .leading, spacing: 2) { + Text(label) + if !description.isEmpty { + Text(description).font(.caption).foregroundStyle(.secondary) + } + } + Spacer(minLength: 0) + } + .contentShape(Rectangle()) + } +} + +// MARK: - Date and slider + +/// Dates are stored as `yyyy-MM-dd` strings; a range as `{ from, to }`. +private let dayFormatter: DateFormatter = { + let formatter = DateFormatter() + formatter.calendar = Calendar(identifier: .gregorian) + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.dateFormat = "yyyy-MM-dd" + return formatter +}() + +struct DatePickerView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + @Environment(\.openUIFormName) private var form + @Environment(FormValidation.self) private var validation: FormValidation? + + var body: some View { + let state = FieldContext(props, context: context, form: form) + if props.string("mode") == "range" { + VStack(alignment: .leading, spacing: 6) { + rangePicker("From", key: "from", state) + rangePicker("To", key: "to", state) + } + .formField(state.field.name, rules: state.rules, value: state.field.value) + } else { + DatePicker( + "", + selection: Binding( + get: { state.field.value.stringValue.flatMap(dayFormatter.date(from:)) ?? Date() }, + set: { set(state, .string(dayFormatter.string(from: $0))) }), + displayedComponents: .date + ) + .labelsHidden() + .disabled(context.isStreaming) + .formField(state.field.name, rules: state.rules, value: state.field.value) + } + } + + private func rangePicker(_ label: String, key: String, _ state: FieldContext) -> some View { + let range = state.field.value.objectValue ?? OpenUIObject() + return DatePicker( + label, + selection: Binding( + get: { range[key]?.stringValue.flatMap(dayFormatter.date(from:)) ?? Date() }, + set: { date in + var next = range + next[key] = .string(dayFormatter.string(from: date)) + set(state, .object(next)) + }), + displayedComponents: .date + ) + .disabled(context.isStreaming) + } + + private func set(_ state: FieldContext, _ value: OpenUIValue) { + state.field.setValue(value) + if !state.rules.isEmpty { + validation?.validateField(state.field.name, value: value, rules: state.rules) + } + } +} + +struct SliderView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + @Environment(\.openUIFormName) private var form + @Environment(FormValidation.self) private var validation: FormValidation? + + var body: some View { + let state = FieldContext(props, context: context, form: form) + let minimum = props.number("min") ?? 0 + let maximum = max(props.number("max") ?? 100, minimum) + let step = props.string("variant") == "discrete" ? max(props.number("step") ?? 1, 0.0001) : nil + let stored = state.field.value.isNullish ? props["defaultValue"] : state.field.value + let values = (stored.arrayValue ?? []).compactMap(\.numberValue) + let current = values.isEmpty ? [minimum] : values + VStack(alignment: .leading, spacing: 4) { + HStack { + Text(props.string("label") ?? state.field.name).font(.subheadline) + Spacer() + Text(current.map(jsNumberToString).joined(separator: " – ")) + .font(.subheadline.monospacedDigit()).foregroundStyle(.secondary) + } + ForEach(current.indices, id: \.self) { index in + let binding = Binding( + get: { min(max(current[index], minimum), maximum) }, + set: { newValue in + var next = current + next[index] = newValue + state.field.setValue(.array(next.map { .number($0) })) + if !state.rules.isEmpty { + validation?.validateField( + state.field.name, value: .number(next[0]), rules: state.rules) + } + }) + if let step { + Slider(value: binding, in: minimum...maximum, step: step) + } else { + Slider(value: binding, in: minimum...maximum) + } + } + } + .disabled(context.isStreaming) + .formField(state.field.name, rules: state.rules, value: state.field.value) + } +} + +// MARK: - Buttons + +struct ButtonView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + @Environment(\.openUIFormName) private var form + @Environment(FormValidation.self) private var validation: FormValidation? + + var body: some View { + let label = props.text("label") + let variant = props.string("variant") ?? "primary" + let destructive = props.string("type") == "destructive" + Button(role: destructive ? .destructive : nil) { + let action = props["action"] + if let validation, variant == "primary", !shouldSkipValidation(action) { + guard validation.validateForm() else { return } + } + context.triggerAction(label, form: form, action: action.isNullish ? nil : action) + } label: { + Text(label) + } + .modifier(ButtonVariant(variant: variant)) + .controlSize(controlSize) + .disabled(context.isStreaming) + } + + /// Primary buttons validate the form first, unless their action plan only + /// has steps that don't submit anything (no @ToAssistant, no mutation). + private func shouldSkipValidation(_ action: OpenUIValue) -> Bool { + guard case .actionPlan(let plan) = action else { return false } + return !plan.steps.contains { step in + switch step { + case .continueConversation: return true + case .run(_, let refType): return refType == .mutation + default: return false + } + } + } + + private var controlSize: ControlSize { + switch props.string("size") { + case "extra-small": return .mini + case "small": return .small + case "large": return .large + default: return .regular + } + } +} + +private struct ButtonVariant: ViewModifier { + let variant: String + + func body(content: Content) -> some View { + switch variant { + case "secondary": content.buttonStyle(.bordered) + case "tertiary", "ghost": content.buttonStyle(.borderless) + default: content.buttonStyle(.borderedProminent) + } + } +} + +struct ButtonsView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + let buttons = props.array("buttons") + if props.string("direction") == "column" { + VStack(alignment: .leading, spacing: theme.compactSpacing) { + ForEach(NodeItem.list(buttons)) { OpenUINode($0.value) } + } + } else { + FlowLayout(spacing: theme.compactSpacing) { + ForEach(NodeItem.list(buttons)) { OpenUINode($0.value) } + } + } + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift new file mode 100644 index 0000000000..86da4fd1be --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift @@ -0,0 +1,440 @@ +import OpenUILang +import SwiftUI + +#if canImport(UIKit) + import UIKit +#else + import AppKit +#endif + +/// Maps lucide icon names (what the model writes) to SF Symbols, with the +/// same category fallbacks as react-ui: an unknown name falls back to its +/// category's representative icon, then to `circle-dot`. +enum LucideSymbols { + static func systemName(for name: String, category: String?) -> String { + let key = name.trimmingCharacters(in: .whitespaces).lowercased() + if let symbol = symbols[key] ?? symbols[aliases[key] ?? ""], exists(symbol) { return symbol } + let fallback = categoryFallbacks[ + category?.trimmingCharacters(in: .whitespaces).lowercased() ?? ""] + if let fallback, let symbol = symbols[fallback], exists(symbol) { return symbol } + return symbols[defaultFallback]! + } + + /// Older OS versions lack some symbols; fall back rather than show nothing. + private static func exists(_ symbol: String) -> Bool { + #if canImport(UIKit) + UIImage(systemName: symbol) != nil + #else + NSImage(systemSymbolName: symbol, accessibilityDescription: nil) != nil + #endif + } + + static let defaultFallback = "circle-dot" + + /// Lucide's renamed icons, mapped to the names in `symbols`. + static let aliases: [String: String] = [ + "triangle-alert": "alert-triangle", "circle-alert": "alert-circle", + "check-circle-2": "check-circle", + "circle-check-big": "circle-check", "chart-no-axes-column": "bar-chart", + "settings-2": "settings", + "house-plus": "house", "utensils-crossed": "utensils", "file-chart-column": "file-text", + "mail-open": "mail", "map-pinned": "map-pin", "sparkle": "sparkles", "dollar": "dollar-sign", + ] + + /// react-ui's `categoryFallbacks`: category → representative lucide name. + static let categoryFallbacks: [String: String] = [ + "accessibility": "accessibility", "account": "user", "animals": "cat", "arrows": "arrow-right", + "brands": "box", "buildings": "building", "charts": "chart-line", + "communication": "message-square", "connectivity": "wifi", "cursors": "mouse-pointer", + "design": "palette", "development": "code", "devices": "smartphone", "emoji": "smile", + "files": "file", "finance": "dollar-sign", "food-beverage": "cooking-pot", "gaming": "gamepad", + "home": "house", "layout": "layout", "mail": "mail", "math": "calculator", + "medical": "heart-pulse", "multimedia": "music", "nature": "tree-pine", + "navigation": "map-pin", "notifications": "bell", "people": "users", + "photography": "camera", "science": "microscope", "seasons": "sun", "security": "shield", + "shapes": "circle", "shopping": "shopping-cart", "social": "share-2", "sports": "trophy", + "sustainability": "leaf", "text": "type", "time": "clock", "tools": "wrench", + "transportation": "car", "travel": "plane", "weather": "cloud", + ] + + static let symbols: [String: String] = [ + "activity": "waveform.path.ecg", + "alarm-clock": "alarm", + "alert-circle": "exclamationmark.circle", + "alert-triangle": "exclamationmark.triangle", + "archive": "archivebox", + "arrow-down": "arrow.down", + "arrow-down-right": "arrow.down.right", + "arrow-left": "arrow.left", + "arrow-right": "arrow.right", + "arrow-up": "arrow.up", + "arrow-up-right": "arrow.up.right", + "award": "rosette", + "baby": "figure.and.child.holdinghands", + "backpack": "backpack", + "badge-check": "checkmark.seal", + "banknote": "banknote", + "bar-chart": "chart.bar", + "bar-chart-2": "chart.bar", + "bath": "bathtub", + "battery": "battery.100", + "bed": "bed.double", + "beer": "mug", + "bell": "bell", + "bike": "bicycle", + "book": "book", + "book-open": "book", + "bookmark": "bookmark", + "box": "shippingbox", + "brain": "brain", + "briefcase": "briefcase", + "bug": "ant", + "building": "building", + "building-2": "building.2", + "bus": "bus", + "cake": "birthday.cake", + "calculator": "function", + "calendar": "calendar", + "calendar-days": "calendar", + "camera": "camera", + "car": "car", + "cart": "cart", + "cat": "cat", + "chart-bar": "chart.bar", + "chart-column": "chart.bar", + "chart-line": "chart.xyaxis.line", + "chart-pie": "chart.pie", + "check": "checkmark", + "check-circle": "checkmark.circle", + "chevron-down": "chevron.down", + "chevron-left": "chevron.left", + "chevron-right": "chevron.right", + "chevron-up": "chevron.up", + "circle": "circle", + "circle-alert": "exclamationmark.circle", + "circle-check": "checkmark.circle", + "circle-dollar-sign": "dollarsign.circle", + "circle-dot": "smallcircle.filled.circle", + "circle-help": "questionmark.circle", + "circle-x": "xmark.circle", + "clapperboard": "movieclapper", + "clipboard": "clipboard", + "clock": "clock", + "cloud": "cloud", + "cloud-rain": "cloud.rain", + "cloud-sun": "cloud.sun", + "code": "chevron.left.forwardslash.chevron.right", + "coffee": "cup.and.saucer", + "coins": "dollarsign.circle", + "compass": "safari", + "cooking-pot": "frying.pan", + "copy": "doc.on.doc", + "cpu": "cpu", + "credit-card": "creditcard", + "crown": "crown", + "database": "cylinder", + "disc-3": "opticaldisc", + "dollar-sign": "dollarsign", + "download": "arrow.down.to.line", + "droplet": "drop", + "dumbbell": "dumbbell", + "edit": "pencil", + "euro": "eurosign", + "external-link": "arrow.up.right.square", + "eye": "eye", + "eye-off": "eye.slash", + "figma": "paintbrush", + "file": "doc", + "file-text": "doc.text", + "film": "film", + "filter": "line.3.horizontal.decrease", + "fish": "fish", + "flag": "flag", + "flame": "flame", + "flask-conical": "flask", + "folder": "folder", + "gamepad": "gamecontroller", + "gamepad-2": "gamecontroller", + "gauge": "gauge.with.dots.needle.33percent", + "gift": "gift", + "git-branch": "arrow.triangle.branch", + "glasses": "eyeglasses", + "globe": "globe", + "graduation-cap": "graduationcap", + "grid": "square.grid.2x2", + "hammer": "hammer", + "hand": "hand.raised", + "hard-drive": "internaldrive", + "hash": "number", + "headphones": "headphones", + "heart": "heart", + "heart-pulse": "heart.text.square", + "help-circle": "questionmark.circle", + "history": "clock.arrow.circlepath", + "home": "house", + "hotel": "bed.double", + "house": "house", + "image": "photo", + "inbox": "tray", + "info": "info.circle", + "key": "key", + "landmark": "building.columns", + "laptop": "laptopcomputer", + "layers": "square.3.layers.3d", + "layout": "rectangle.3.group", + "layout-dashboard": "rectangle.3.group", + "leaf": "leaf", + "lightbulb": "lightbulb", + "line-chart": "chart.xyaxis.line", + "link": "link", + "list": "list.bullet", + "list-checks": "checklist", + "loader": "arrow.triangle.2.circlepath", + "lock": "lock", + "log-in": "arrow.right.to.line", + "log-out": "rectangle.portrait.and.arrow.right", + "mail": "envelope", + "map": "map", + "map-pin": "mappin.and.ellipse", + "medal": "medal", + "megaphone": "megaphone", + "menu": "line.3.horizontal", + "message-circle": "message", + "message-square": "bubble.left", + "mic": "mic", + "microscope": "microbe", + "minus": "minus", + "monitor": "display", + "moon": "moon", + "more-horizontal": "ellipsis", + "mountain": "mountain.2", + "mouse-pointer": "cursorarrow", + "music": "music.note", + "navigation": "location.north", + "newspaper": "newspaper", + "notebook": "book.closed", + "package": "shippingbox", + "palette": "paintpalette", + "paperclip": "paperclip", + "pause": "pause", + "pen": "pencil", + "pencil": "pencil", + "percent": "percent", + "phone": "phone", + "pie-chart": "chart.pie", + "pill": "pills", + "pizza": "fork.knife", + "plane": "airplane", + "play": "play", + "plug": "powerplug", + "plus": "plus", + "pound-sterling": "sterlingsign", + "power": "power", + "printer": "printer", + "puzzle": "puzzlepiece", + "receipt": "receipt", + "refresh-cw": "arrow.clockwise", + "rocket": "paperplane", + "rotate-ccw": "arrow.counterclockwise", + "route": "point.topleft.down.to.point.bottomright.curvepath", + "ruler": "ruler", + "save": "square.and.arrow.down", + "scale": "scalemass", + "school": "building.columns", + "scissors": "scissors", + "search": "magnifyingglass", + "send": "paperplane", + "server": "server.rack", + "settings": "gearshape", + "share": "square.and.arrow.up", + "share-2": "square.and.arrow.up", + "shield": "shield", + "shield-check": "checkmark.shield", + "ship": "ferry", + "shirt": "tshirt", + "shopping-bag": "bag", + "shopping-cart": "cart", + "smartphone": "iphone", + "smile": "face.smiling", + "snowflake": "snowflake", + "sparkles": "sparkles", + "speaker": "hifispeaker", + "square": "square", + "star": "star", + "stethoscope": "stethoscope", + "store": "storefront", + "sun": "sun.max", + "sunrise": "sunrise", + "sunset": "sunset", + "swords": "figure.fencing", + "tablet": "ipad", + "tag": "tag", + "target": "scope", + "tent": "tent", + "terminal": "apple.terminal", + "thermometer": "thermometer.medium", + "thumbs-down": "hand.thumbsdown", + "thumbs-up": "hand.thumbsup", + "ticket": "ticket", + "timer": "timer", + "train": "tram", + "train-front": "tram", + "trash": "trash", + "trash-2": "trash", + "tree-pine": "tree", + "trees": "tree", + "trending-down": "chart.line.downtrend.xyaxis", + "trending-up": "chart.line.uptrend.xyaxis", + "trophy": "trophy", + "truck": "truck.box", + "tv": "tv", + "type": "textformat", + "umbrella": "umbrella", + "upload": "arrow.up.to.line", + "user": "person", + "user-check": "person.crop.circle.badge.checkmark", + "user-minus": "person.badge.minus", + "user-plus": "person.badge.plus", + "users": "person.2", + "utensils": "fork.knife", + "video": "video", + "volume-2": "speaker.wave.2", + "wallet": "wallet.bifold", + "watch": "applewatch", + "waves": "water.waves", + "wifi": "wifi", + "wind": "wind", + "wine": "wineglass", + "wrench": "wrench.adjustable", + "x": "xmark", + "zap": "bolt", + "accessibility": "accessibility", + "mouse": "computermouse", + ] +} + +/// The SF Symbol for an `Icon` element value (or nil when the value isn't one). +func iconSymbol(_ value: OpenUIValue) -> String? { + guard let icon = value.elementValue, icon.typeName == "Icon", + let name = icon.props["name"]?.stringValue, !name.isEmpty + else { return nil } + return LucideSymbols.systemName(for: name, category: icon.props["category"]?.stringValue) +} + +struct IconView: View { + let props: ComponentProps + + var body: some View { + if let name = props.string("name"), !name.isEmpty { + Image(systemName: LucideSymbols.systemName(for: name, category: props.string("category"))) + } + } +} + +struct IconButtonView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + @Environment(\.openUIFormName) private var form + + var body: some View { + let label = props.text("name") + let symbol = + iconSymbol(props["icon"]) ?? LucideSymbols.systemName(for: "circle-dot", category: nil) + let circle = props.string("shape") == "circle" + Button { + let action = props["action"] + context.triggerAction(label, form: form, action: action.isNullish ? nil : action) + } label: { + Image(systemName: symbol) + .frame(width: 18, height: 18) + .padding(4) + } + .modifier(IconButtonStyle(variant: props.string("variant") ?? "primary", circle: circle)) + .controlSize(controlSize) + .accessibilityLabel(label) + .disabled(context.isStreaming) + } + + private var controlSize: ControlSize { + switch props.string("size") { + case "extra-small": return .mini + case "small": return .small + case "large": return .large + default: return .regular + } + } +} + +private struct IconButtonStyle: ViewModifier { + let variant: String + let circle: Bool + + func body(content: Content) -> some View { + let styled = Group { + switch variant { + case "secondary": content.buttonStyle(.bordered) + case "tertiary": content.buttonStyle(.borderless) + default: content.buttonStyle(.borderedProminent) + } + } + if circle { + styled.buttonBorderShape(.circle) + } else { + styled.buttonBorderShape(.roundedRectangle) + } + } +} + +struct TagView: View { + let props: ComponentProps + var body: some View { + TagLabel( + text: props.text("text"), symbol: iconSymbol(props["icon"]), size: props.string("size"), + variant: props.string("variant")) + } +} + +/// A small pill with optional icon, tinted by status variant. +struct TagLabel: View { + let text: String + let symbol: String? + let size: String? + let variant: String? + @Environment(\.openUITagOnImage) private var onImage + + var body: some View { + let neutral = variant == nil || variant == "neutral" + let color = neutral ? Color.secondary : statusColor(variant) + HStack(spacing: 4) { + if let symbol { Image(systemName: symbol) } + Text(text) + } + .font(font) + .foregroundStyle(onImage ? Color.white : neutral ? Color.primary : color) + .padding(.horizontal, 8) + .padding(.vertical, 3) + // On a photo the variant tint isn't readable, so react-ui switches every + // tag to white on translucent black there. + .background(onImage ? Color.black.opacity(0.4) : color.opacity(0.12), in: Capsule()) + } + + private var font: Font { + switch size { + case "sm": return .caption2.weight(.medium) + case "lg": return .callout.weight(.medium) + default: return .caption.weight(.medium) + } + } +} + +private struct TagOnImageKey: EnvironmentKey { + static let defaultValue = false +} + +extension EnvironmentValues { + /// True for tags drawn over an image, like a visual card's. + var openUITagOnImage: Bool { + get { self[TagOnImageKey.self] } + set { self[TagOnImageKey.self] = newValue } + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift new file mode 100644 index 0000000000..db30dc2ebc --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift @@ -0,0 +1,369 @@ +import OpenUILang +import SwiftUI + +// MARK: - Table + +/// Column-oriented table: each `Col` holds its own data array. Cells can be +/// text or elements (e.g. buttons from `@Each`). Long tables page by 10 rows. +struct TableView: View { + let props: ComponentProps + @State private var page = 0 + @Environment(\.openUITheme) private var theme + + private static let pageSize = 10 + + var body: some View { + let columns = props.children("columns") + let data = columns.map { column -> [OpenUIValue] in + let raw = column["data"] + if case .array(let items) = raw { return items } + return raw.isNullish ? [] : [raw] + } + let rowCount = data.map(\.count).max() ?? 0 + let pages = max(1, Int((Double(rowCount) / Double(Self.pageSize)).rounded(.up))) + let current = min(page, pages - 1) + let rows = Array( + stride(from: current * Self.pageSize, to: min(rowCount, (current + 1) * Self.pageSize), by: 1) + ) + + VStack(alignment: .leading, spacing: theme.compactSpacing) { + ScrollView(.horizontal, showsIndicators: false) { + Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 8) { + GridRow { + ForEach(Array(columns.enumerated()), id: \.offset) { index, column in + Text(column.text("label")) + .font(.subheadline.weight(.semibold)) + .gridColumnAlignment(isNumeric(column) ? .trailing : .leading) + } + } + Divider() + ForEach(rows, id: \.self) { row in + GridRow { + ForEach(Array(columns.enumerated()), id: \.offset) { index, column in + cell(row < data[index].count ? data[index][row] : .null, numeric: isNumeric(column)) + } + } + if row != rows.last { Divider().opacity(0.5) } + } + } + .padding(.vertical, 4) + } + if pages > 1 { + HStack { + Button("Previous") { page = max(0, current - 1) }.disabled(current == 0) + Spacer() + Text("\(current + 1) / \(pages)").font(.caption.monospacedDigit()).foregroundStyle( + .secondary) + Spacer() + Button("Next") { page = min(pages - 1, current + 1) }.disabled(current >= pages - 1) + } + .buttonStyle(.borderless) + .font(.caption) + } + } + } + + private func isNumeric(_ column: ComponentProps) -> Bool { column.string("type") == "number" } + + @ViewBuilder + private func cell(_ value: OpenUIValue, numeric: Bool) -> some View { + switch value { + case .element, .array: + OpenUINode(value) + default: + Text(displayText(value)) + .font(numeric ? .callout.monospacedDigit() : .callout) + } + } +} + +struct ColView: View { + let props: ComponentProps + + var body: some View { + VStack(alignment: .leading, spacing: 4) { + Text(props.text("label")).font(.subheadline.weight(.semibold)) + OpenUINodes(props.array("data"), spacing: 4) + } + } +} + +// MARK: - Lists + +struct ListBlockView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + + var body: some View { + let numbered = props.string("variant") != "image" + let small = props.string("size") == "small" + VStack(alignment: .leading, spacing: small ? 6 : 10) { + ForEach(Array(props.children("items").enumerated()), id: \.offset) { index, item in + ListRow( + item: item, marker: numbered ? "\(index + 1)" : nil, small: small, + onTap: item["action"].isNullish + ? nil + : { context.triggerAction(item.text("title"), action: item["action"]) }) + } + } + } +} + +struct ListItemView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + + var body: some View { + ListRow( + item: props, marker: nil, small: false, + onTap: props["action"].isNullish + ? nil : { context.triggerAction(props.text("title"), action: props["action"]) }) + } +} + +/// A list row: marker or image, title and subtitle, clickable only with an action. +private struct ListRow: View { + let item: ComponentProps + let marker: String? + let small: Bool + let onTap: (() -> Void)? + @Environment(\.openUITheme) private var theme + + var body: some View { + let row = HStack(alignment: .top, spacing: 10) { + if let marker { + Text(marker) + .font(.caption.weight(.semibold).monospacedDigit()) + .frame(width: 22, height: 22) + .background(theme.sunkSurface, in: Circle()) + } else if let src = item["image"]["src"].stringValue { + RemoteImage(src: src, alt: displayText(item["image"]["alt"])) + .frame(width: 44, height: 44) + } + VStack(alignment: .leading, spacing: 2) { + Text(item.text("title")).font(small ? .subheadline : .body) + if let subtitle = item.string("subtitle"), !subtitle.isEmpty { + Text(subtitle).font(.caption).foregroundStyle(.secondary) + } + } + Spacer(minLength: 0) + if onTap != nil { + if let actionLabel = item.string("actionLabel"), !actionLabel.isEmpty { + Text(actionLabel).font(.caption.weight(.medium)).foregroundStyle(Color.accentColor) + } else { + Image(systemName: "chevron.right").font(.caption).foregroundStyle(.secondary) + } + } + } + .contentShape(Rectangle()) + if let onTap { + Button(action: onTap) { row }.buttonStyle(.plain) + } else { + row + } + } +} + +struct FollowUpBlockView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + + var body: some View { + VStack(alignment: .leading, spacing: 6) { + ForEach(Array(props.children("items").enumerated()), id: \.offset) { _, item in + FollowUpButton(text: item.text("text")) { context.triggerAction(item.text("text")) } + } + } + .disabled(context.isStreaming) + } +} + +struct FollowUpItemView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + + var body: some View { + FollowUpButton(text: props.text("text")) { context.triggerAction(props.text("text")) } + .disabled(context.isStreaming) + } +} + +/// A suggested next message; tapping it sends the text as the user's message. +private struct FollowUpButton: View { + let text: String + let action: () -> Void + + var body: some View { + Button(action: action) { + HStack(spacing: 6) { + Image(systemName: "arrow.turn.down.right").font(.caption) + Text(text).multilineTextAlignment(.leading) + } + .font(.subheadline) + } + .buttonStyle(.borderless) + } +} + +struct StepsView: View { + let props: ComponentProps + + var body: some View { + let items = props.children("items") + VStack(alignment: .leading, spacing: 0) { + ForEach(Array(items.enumerated()), id: \.offset) { index, item in + HStack(alignment: .top, spacing: 12) { + VStack(spacing: 0) { + Text("\(index + 1)") + .font(.caption.weight(.bold).monospacedDigit()) + .foregroundStyle(.white) + .frame(width: 22, height: 22) + .background(Color.accentColor, in: Circle()) + if index < items.count - 1 { + Rectangle().fill(.secondary.opacity(0.3)).frame(width: 2).frame(maxHeight: .infinity) + } + } + StepContent(item: item).padding(.bottom, index < items.count - 1 ? 14 : 0) + } + } + } + } +} + +struct StepsItemView: View { + let props: ComponentProps + var body: some View { StepContent(item: props) } +} + +private struct StepContent: View { + let item: ComponentProps + + var body: some View { + VStack(alignment: .leading, spacing: 2) { + Text(item.text("title")).font(.subheadline.weight(.semibold)) + InlineMarkdown(item.text("details")).font(.subheadline).foregroundStyle(.secondary) + } + .frame(maxWidth: .infinity, alignment: .leading) + } +} + +// MARK: - Tabs, accordions and sections + +struct TabsView: View { + let props: ComponentProps + @State private var selected: String? + @Environment(\.openUITheme) private var theme + + var body: some View { + let items = props.children("items") + let current = selected ?? items.first?.text("value") + VStack(alignment: .leading, spacing: theme.spacing) { + Picker("", selection: Binding(get: { current ?? "" }, set: { selected = $0 })) { + ForEach(Array(items.enumerated()), id: \.offset) { _, item in + Text(item.text("trigger")).tag(item.text("value")) + } + } + .pickerStyle(.segmented) + .labelsHidden() + if let item = items.first(where: { $0.text("value") == current }) { + OpenUINodes(item.array("content")) + } + } + } +} + +struct AccordionView: View { + let props: ComponentProps + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + let items = props.children("items") + ForEach(Array(items.enumerated()), id: \.offset) { index, item in + Disclosure( + trigger: item.text("trigger"), content: item.array("content"), initiallyOpen: false) + if index < items.count - 1 { Divider() } + } + } + } +} + +struct SectionBlockView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + let sections = props.children("sections") + let foldable = props.bool("isFoldable") ?? true + VStack(alignment: .leading, spacing: foldable ? 0 : theme.spacing) { + ForEach(Array(sections.enumerated()), id: \.offset) { index, section in + if foldable { + // Sections open by default so they reveal content as it streams in. + Disclosure( + trigger: section.text("trigger"), content: section.array("content"), initiallyOpen: true + ) + if index < sections.count - 1 { Divider() } + } else { + VStack(alignment: .leading, spacing: theme.compactSpacing) { + Text(section.text("trigger")).font(.headline) + OpenUINodes(section.array("content")) + } + } + } + } + } +} + +/// A sub-item rendered on its own: its trigger as a heading, then its content. +struct TriggeredContentView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + VStack(alignment: .leading, spacing: theme.compactSpacing) { + Text(props.text("trigger")).font(.headline) + OpenUINodes(props.array("content")) + } + } +} + +private struct Disclosure: View { + let trigger: String + let content: [OpenUIValue] + @State private var isOpen: Bool + + init(trigger: String, content: [OpenUIValue], initiallyOpen: Bool) { + self.trigger = trigger + self.content = content + _isOpen = State(initialValue: initiallyOpen) + } + + var body: some View { + DisclosureGroup(isExpanded: $isOpen) { + OpenUINodes(content).padding(.top, 6) + } label: { + Text(trigger).font(.subheadline.weight(.semibold)) + } + .padding(.vertical, 8) + } +} + +// MARK: - Carousel + +/// Slides scroll horizontally; each slide is an array of content. +struct CarouselView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + ScrollView(.horizontal, showsIndicators: false) { + HStack(alignment: .top, spacing: theme.spacing) { + ForEach(Array(props.array("children").enumerated()), id: \.offset) { _, slide in + OpenUINodes(slide.arrayValue ?? [slide]) + .frame(width: 260, alignment: .topLeading) + .surface(props.string("variant") ?? "card") + } + } + .padding(.vertical, 2) + } + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift new file mode 100644 index 0000000000..bfb9a39ace --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift @@ -0,0 +1,267 @@ +import OpenUILang +import SwiftUI + +// MARK: - Shared selection model + +/// The selected values of a single- or multiple-choice field, following +/// react-ui's `normalizeSelection`: a single choice is stored as a string, +/// multiple choices as a string array; unset fields fall back to `defaultValue`. +private func selection(stored: OpenUIValue, defaultValue: OpenUIValue, single: Bool) -> [String] { + func strings(_ value: OpenUIValue) -> [String]? { + switch value { + case .string(let string): return string.isEmpty ? [] : [string] + case .array(let items): return items.compactMap(\.stringValue) + default: return nil + } + } + let values = strings(stored) ?? strings(defaultValue) ?? [] + return single ? Array(values.prefix(1)) : values +} + +/// How a selection is stored (`getStoredDefaultValue` / the change handlers). +private func storedSelection(_ values: [String], single: Bool) -> OpenUIValue { + if single { return values.first.map(OpenUIValue.string) ?? .undefined } + return .array(values.map(OpenUIValue.string)) +} + +/// Field plumbing shared by Chips and OptionCards. +private struct SelectionField: View { + let props: ComponentProps + let componentType: String + @ViewBuilder let option: (ComponentProps, Bool, @escaping () -> Void) -> Option + @Environment(OpenUIContext.self) private var context + @Environment(\.openUIFormName) private var form + @Environment(FormValidation.self) private var validation: FormValidation? + + var body: some View { + let single = props.string("type") == "single" + let field = context.stateField(name: props.text("name"), binding: props["value"], form: form) + let rules = parseStructuredRules(props["rules"]) + let selected = selection( + stored: field.value, defaultValue: props["defaultValue"], single: single) + FlowLayout(spacing: 8) { + ForEach(Array(props.children("items").enumerated()), id: \.offset) { _, item in + let value = item.text("value") + option(item, selected.contains(value)) { + var next = selected + if single { + next = selected == [value] ? [] : [value] + } else if let index = next.firstIndex(of: value) { + next.remove(at: index) + } else { + next.append(value) + } + let stored = storedSelection(next, single: single) + field.setValue(stored) + if !rules.isEmpty { + validation?.validateField(field.name, value: stored, rules: rules) + } + } + .disabled(item.bool("disabled") == true) + } + } + .disabled(context.isStreaming) + .formField(field.name, rules: rules, value: field.value) + .onAppear { seedDefault(single: single, field: field) } + .onChange(of: context.isStreaming) { seedDefault(single: single, field: field) } + } + + /// Stores the default once streaming ends, without notifying the host. + private func seedDefault(single: Bool, field: StateField) { + guard !field.isReactive else { return } + let defaults = selection( + stored: .undefined, defaultValue: props["defaultValue"], single: single) + guard !defaults.isEmpty else { return } + context.setDefaultValue( + form: form, componentType: componentType, name: field.name, + value: storedSelection(defaults, single: single)) + } +} + +// MARK: - Chips + +struct ChipsView: View { + let props: ComponentProps + var body: some View { + SelectionField(props: props, componentType: "Chips") { item, isOn, toggle in + Chip(item: item, isOn: isOn, action: toggle) + } + } +} + +struct ChipItemView: View { + let props: ComponentProps + var body: some View { Chip(item: props, isOn: false, action: {}) } +} + +private struct Chip: View { + let item: ComponentProps + let isOn: Bool + let action: () -> Void + @Environment(\.openUITheme) private var theme + + var body: some View { + Button(action: action) { + HStack(spacing: 4) { + if let symbol = iconSymbol(item["icon"]) { Image(systemName: symbol) } + Text(item.text("label")) + } + .font(.subheadline) + .padding(.horizontal, 12) + .padding(.vertical, 6) + .foregroundStyle(isOn ? Color.white : Color.primary) + .background(isOn ? Color.accentColor : theme.sunkSurface, in: Capsule()) + .overlay(Capsule().strokeBorder(isOn ? Color.clear : theme.border)) + } + .buttonStyle(.plain) + .accessibilityAddTraits(isOn ? .isSelected : []) + } +} + +// MARK: - Option cards + +struct OptionCardsView: View { + let props: ComponentProps + var body: some View { + SelectionField(props: props, componentType: "OptionCards") { item, isOn, toggle in + OptionCardTile(item: item, isOn: isOn, action: toggle) + } + } +} + +struct OptionCardView: View { + let props: ComponentProps + var body: some View { OptionCardTile(item: props, isOn: false, action: {}) } +} + +private struct OptionCardTile: View { + let item: ComponentProps + let isOn: Bool + let action: () -> Void + @Environment(\.openUITheme) private var theme + + var body: some View { + Button(action: action) { + VStack(alignment: .leading, spacing: 6) { + switch item["topContent"] { + case .element(let element) where element.typeName == "Icon": + Image(systemName: iconSymbol(item["topContent"]) ?? "circle").font(.title2) + .foregroundStyle(Color.accentColor) + case .element: + OpenUINode(item["topContent"]).frame(height: 90).clipped() + default: + EmptyView() + } + Text(item.text("title")).font(.subheadline.weight(.semibold)) + if let subtitle = item.string("subtitle"), !subtitle.isEmpty { + Text(subtitle).font(.caption).foregroundStyle(.secondary) + } + } + .padding(12) + .frame(width: 160, alignment: .topLeading) + .background(theme.surface, in: RoundedRectangle(cornerRadius: theme.cornerRadius)) + .overlay( + RoundedRectangle(cornerRadius: theme.cornerRadius) + .strokeBorder(isOn ? Color.accentColor : theme.border, lineWidth: isOn ? 2 : 1)) + } + .buttonStyle(.plain) + .accessibilityAddTraits(isOn ? .isSelected : []) + } +} + +// MARK: - Editable table + +/// A spreadsheet-like table. Edits stay local until Save, which stores the rows +/// as `{ id, values }` under the table's name and sends "Save Changes", as in +/// react-ui. +struct EditableTableView: View { + let props: ComponentProps + @State private var edits: [String: [Int: String]] = [:] + @Environment(OpenUIContext.self) private var context + @Environment(\.openUITheme) private var theme + + var body: some View { + let columns = props.array("columns") + let rows = props.array("data") + let name = props.string("name") ?? "editable-table" + let changed = edits.values.reduce(0) { $0 + $1.count } + VStack(alignment: .leading, spacing: theme.compactSpacing) { + ScrollView(.horizontal, showsIndicators: false) { + Grid(alignment: .leading, horizontalSpacing: 10, verticalSpacing: 6) { + GridRow { + ForEach(Array(columns.enumerated()), id: \.offset) { _, column in + Text(displayText(column["header"].isNullish ? column["key"] : column["header"])) + .font(.subheadline.weight(.semibold)) + } + } + Divider() + ForEach(Array(rows.enumerated()), id: \.offset) { _, row in + let id = displayText(row["id"]) + GridRow { + ForEach(Array(columns.enumerated()), id: \.offset) { index, column in + cell( + rowId: id, index: index, column: column, + value: row["values"].arrayValue?[safe: index]) + } + } + } + } + } + if changed > 0 { + HStack { + Text("\(changed) unsaved change\(changed == 1 ? "" : "s")").font(.caption) + .foregroundStyle(.secondary) + Spacer() + Button("Reset") { edits = [:] }.buttonStyle(.borderless) + Button("Save Changes") { + let saved = OpenUIValue.array( + rows.map { row in + let id = displayText(row["id"]) + let values = (0.. OpenUIValue in + if let edit = edits[id]?[index] { + let number = jsStringToNumber(edit) + let numeric = columns[index]["type"].stringValue == "number" && !number.isNaN + return numeric ? .number(number) : .string(edit) + } + return row["values"].arrayValue?[safe: index] ?? .null + } + return ["id": row["id"], "values": .array(values)] + }) + context.runtime.setFieldValue( + form: name, componentType: "EditableTable", name: name, value: saved) + context.triggerAction("Save Changes", form: name) + edits = [:] + } + .buttonStyle(.borderedProminent) + } + } + } + .disabled(context.isStreaming) + } + + private func cell(rowId: String, index: Int, column: OpenUIValue, value: OpenUIValue?) + -> some View + { + let width = column["width"].numberValue.map { CGFloat($0) } ?? 120 + let binding = Binding( + get: { edits[rowId]?[index] ?? displayText(value ?? .null) }, + set: { edits[rowId, default: [:]][index] = $0 }) + return Group { + if column["type"].stringValue == "select", let options = column["options"].arrayValue { + Picker("", selection: binding) { + ForEach(Array(options.enumerated()), id: \.offset) { _, option in + Text(displayText(option["label"])).tag(displayText(option["value"])) + } + } + .labelsHidden() + } else { + TextField("", text: binding).textFieldStyle(.roundedBorder) + } + } + .frame(width: width) + } +} + +extension Array { + subscript(safe index: Int) -> Element? { indices.contains(index) ? self[index] : nil } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/FormValidation.swift b/packages/swift-lang/Sources/OpenUISwiftUI/FormValidation.swift new file mode 100644 index 0000000000..490a0d8409 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/FormValidation.swift @@ -0,0 +1,103 @@ +import Observation +import OpenUILang +import SwiftUI + +/// Validation state for one `Form`: fields register their rules, primary +/// buttons validate the whole form before acting, and fields show their error. +/// Ports react-lang's `useCreateFormValidation`. +@MainActor +@Observable +public final class FormValidation { + public private(set) var errors: [String: String] = [:] + + private struct Registration { + var rules: [ParsedRule] + var value: @MainActor () -> OpenUIValue + } + + @ObservationIgnored private var fields: [String: Registration] = [:] + + public init() {} + + public func error(for name: String) -> String? { errors[name] } + + public func register( + _ name: String, rules: [ParsedRule], value: @escaping @MainActor () -> OpenUIValue + ) { + fields[name] = Registration(rules: rules, value: value) + } + + public func unregister(_ name: String) { + fields[name] = nil + } + + /// Validates one field, storing or clearing its error. Returns whether it is valid. + @discardableResult + public func validateField(_ name: String, value: OpenUIValue, rules: [ParsedRule]) -> Bool { + let error = validate(value, rules) + if errors[name] != error { errors[name] = error } + return error == nil + } + + /// Validates every registered field. Returns whether the form is valid. + public func validateForm() -> Bool { + var next: [String: String] = [:] + for (name, field) in fields { + if let error = validate(unwrapFieldValue(field.value()), field.rules) { next[name] = error } + } + errors = next + return next.isEmpty + } + + public func clearError(_ name: String) { + if errors[name] != nil { errors[name] = nil } + } +} + +/// Form fields store `{ value, componentType }`; validation sees the raw value. +private func unwrapFieldValue(_ value: OpenUIValue) -> OpenUIValue { + if case .object(let object) = value, object.contains("componentType"), let inner = object["value"] + { + return inner + } + return value +} + +/// Registers a field's rules with the enclosing form while it is on screen. +struct FormFieldRegistration: ViewModifier { + let name: String + let rules: [ParsedRule] + let value: OpenUIValue + @Environment(FormValidation.self) private var validation: FormValidation? + @Environment(OpenUIContext.self) private var context + + func body(content: Content) -> some View { + content + .onChange( + of: RegistrationKey(name: name, rules: rules, isStreaming: context.isStreaming), + initial: true + ) { + guard let validation, !rules.isEmpty, !context.isStreaming else { return } + let current = value + validation.register(name, rules: rules) { current } + } + .onChange(of: value) { + guard let validation, !rules.isEmpty, !context.isStreaming else { return } + let current = value + validation.register(name, rules: rules) { current } + } + .onDisappear { validation?.unregister(name) } + } + + private struct RegistrationKey: Equatable { + let name: String + let rules: [ParsedRule] + let isStreaming: Bool + } +} + +extension View { + func formField(_ name: String, rules: [ParsedRule], value: OpenUIValue) -> some View { + modifier(FormFieldRegistration(name: name, rules: rules, value: value)) + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIChatLibrary.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIChatLibrary.swift new file mode 100644 index 0000000000..b17bc40fc6 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIChatLibrary.swift @@ -0,0 +1,116 @@ +import OpenUILang +import SwiftUI + +/// The OpenUI chat library rendered with native SwiftUI views. Component names +/// and arguments match `openuiChatLibrary` from @openuidev/react-ui (see +/// `ChatComponents`), and the root is `Card`. +public enum OpenUIChatLibrary { + @MainActor + public static let library = SwiftUILibrary( + components: ChatComponents.all.map { schema in + SwiftUIComponent(schema, content: views[schema.name] ?? { _ in AnyView(EmptyView()) }) + }, + root: "Card", + componentGroups: ChatComponents.groups) + + /// Sub-components that only carry data for their parent (a chart reads its + /// `Series`); they render nothing on their own. + static let dataOnly: Set = ["Series", "ScatterSeries", "Point", "Slice"] + + @MainActor + static let views: [String: ComponentContent] = { + func make(_ view: @escaping @MainActor (ComponentProps) -> V) -> ComponentContent { + { AnyView(view($0)) } + } + return [ + // Content + "Card": make(CardView.init), + "CardHeader": make(CardHeaderView.init), + "TextContent": make(TextContentView.init), + "MarkDownRenderer": make(MarkDownRendererView.init), + "Callout": make(CalloutView.init), + "TextCallout": make(TextCalloutView.init), + "CodeBlock": make(CodeBlockView.init), + "Image": make(ImageView.init), + "ImageBlock": make(ImageBlockView.init), + "ImageGallery": make(ImageGalleryView.init), + "Separator": make(SeparatorView.init), + "InlineHeader": make(InlineHeaderView.init), + // Tables + "Table": make(TableView.init), + "Col": make(ColView.init), + "EditableTable": make(EditableTableView.init), + // Charts + "BarChart": make(BarChartView.init), + "LineChart": make(LineChartView.init), + "AreaChart": make(AreaChartView.init), + "RadarChart": make(RadarChartView.init), + "HorizontalBarChart": make(HorizontalBarChartView.init), + "PieChart": make(PieChartView.init), + "RadialChart": make(RadialChartView.init), + "SingleStackedBarChart": make(SingleStackedBarChartView.init), + "ScatterChart": make(ScatterChartView.init), + // Forms + "Form": make(FormView.init), + "FormControl": make(FormControlView.init), + "Label": make(LabelView.init), + "Input": make(InputView.init), + "TextArea": make(TextAreaView.init), + "Select": make(SelectView.init), + "SelectItem": make(SelectItemView.init), + "DatePicker": make(DatePickerView.init), + "Slider": make(SliderView.init), + "CheckBoxGroup": make(CheckBoxGroupView.init), + "CheckBoxItem": make(CheckBoxItemView.init), + "RadioGroup": make(RadioGroupView.init), + "RadioItem": make(RadioItemView.init), + "SwitchGroup": make(SwitchGroupView.init), + "SwitchItem": make(SwitchItemView.init), + "Chips": make(ChipsView.init), + "ChipItem": make(ChipItemView.init), + "OptionCards": make(OptionCardsView.init), + "OptionCard": make(OptionCardView.init), + // Buttons and icons + "Button": make(ButtonView.init), + "Buttons": make(ButtonsView.init), + "Icon": make(IconView.init), + "IconButton": make(IconButtonView.init), + // Lists and layout + "ListBlock": make(ListBlockView.init), + "ListItem": make(ListItemView.init), + "FollowUpBlock": make(FollowUpBlockView.init), + "FollowUpItem": make(FollowUpItemView.init), + "SectionBlock": make(SectionBlockView.init), + "SectionItem": make(TriggeredContentView.init), + "Tabs": make(TabsView.init), + "TabItem": make(TriggeredContentView.init), + "Accordion": make(AccordionView.init), + "AccordionItem": make(TriggeredContentView.init), + "Steps": make(StepsView.init), + "StepsItem": make(StepsItemView.init), + "Carousel": make(CarouselView.init), + // Data display + "TagBlock": make(TagBlockView.init), + "Tag": make(TagView.init), + "EntityList": make(EntityListView.init), + // Cards and their building blocks + "SnippetCardBlock": make(SnippetCardBlockView.init), + "SnippetCardItem": make(SnippetCardItemView.init), + "OverviewCardBlock": make(OverviewCardBlockView.init), + "OverviewCardItem": make(OverviewCardItemView.init), + "ContextCardBlock": make(ContextCardBlockView.init), + "ContextCardItem": make(ContextCardItemView.init), + "CompositeCardBlock": make(CompositeCardBlockView.init), + "CompositeCardItem": make(CompositeCardItemView.init), + "VisualCardBlock": make(VisualCardBlockView.init), + "VisualCardItem": make(VisualCardItemView.init), + "Text": make { TextLineView(props: $0, bold: false) }, + "BoldText": make { TextLineView(props: $0, bold: true) }, + "IconText": make(IconTextView.init), + "ImageText": make(ImageTextView.init), + "ImageTextLarge": make(ImageTextLargeView.init), + "MetricIndicatorInline": make(MetricIndicatorInlineView.init), + "MetricIndicatorWithStrikethrough": make(MetricIndicatorWithStrikethroughView.init), + ] + }() +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift new file mode 100644 index 0000000000..4486968184 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift @@ -0,0 +1,120 @@ +import Observation +import OpenUILang +import SwiftUI + +/// How a component renders: it receives its evaluated props and returns a view. +public typealias ComponentContent = @MainActor (ComponentProps) -> AnyView + +/// A SwiftUI component library. +public typealias SwiftUILibrary = Library + +/// A component definition rendered with SwiftUI. +public typealias SwiftUIComponent = ComponentDefinition + +extension ComponentDefinition where Content == ComponentContent { + /// Pairs a schema with the SwiftUI view that renders it. + public init( + _ schema: ComponentSchema, @ViewBuilder view: @escaping @MainActor (ComponentProps) -> V + ) { + self.init(schema, content: { AnyView(view($0)) }) + } +} + +/// The renderer state shared with every component through the environment: +/// the runtime, streaming status, form fields and actions. Observing it +/// re-renders the tree when state or query results change. +@MainActor +@Observable +public final class OpenUIContext { + public let runtime: OpenUIRuntime + public let library: SwiftUILibrary + + /// Bumped whenever the response, `$state` or query results change. + public private(set) var revision = 0 + + @ObservationIgnored var onAction: ((ActionEvent) -> Void)? + @ObservationIgnored var onStateUpdate: ((OpenUIObject) -> Void)? + @ObservationIgnored private var unsubscribers: [() -> Void] = [] + + public init( + library: SwiftUILibrary, initialState: OpenUIObject? = nil, + toolProvider: (any ToolProvider)? = nil + ) { + self.library = library + self.runtime = OpenUIRuntime( + library: library, initialState: initialState, toolProvider: toolProvider) + runtime.onAction = { [weak self] event in self?.onAction?(event) } + runtime.onStateUpdate = { [weak self] state in self?.onStateUpdate?(state) } + unsubscribers.append(runtime.store.subscribe { [weak self] in self?.revision += 1 }) + unsubscribers.append(runtime.queries.subscribe { [weak self] in self?.revision += 1 }) + } + + /// Feeds the latest response text. + public func update(response: String?, isStreaming: Bool) { + runtime.update(response: response, isStreaming: isStreaming) + revision += 1 + } + + /// The evaluated root element for the current state. + public var root: ElementNode? { + _ = revision + return runtime.evaluatedRoot() + } + + public var isStreaming: Bool { + _ = revision + return runtime.isStreaming + } + + public var isQueryLoading: Bool { + _ = revision + return runtime.queries.isAnyLoading + } + + /// Runs a component's action (see `OpenUIRuntime.triggerAction`). + public func triggerAction(_ label: String, form: String? = nil, action: OpenUIValue? = nil) { + Task { await runtime.triggerAction(label, form: form, action: action) } + } + + /// The form field or `$binding` a component reads and writes. + public func stateField(name: String, binding: OpenUIValue, form: String?) -> StateField { + _ = revision + return runtime.stateField(name: name, binding: binding, form: form) + } + + public func fieldValue(form: String?, name: String) -> OpenUIValue { + _ = revision + return runtime.fieldValue(form: form, name: name) + } + + /// Seeds a field's default once streaming ends, without notifying the host + /// (react-lang's `useSetDefaultValue`). + public func setDefaultValue( + form: String?, componentType: String, name: String, value: OpenUIValue + ) { + guard !runtime.isStreaming, !value.isNullish, + runtime.fieldValue(form: form, name: name) == .undefined + else { return } + runtime.setFieldValue( + form: form, componentType: componentType, name: name, value: value, notifyHost: false) + } + + /// Stops query refreshes and drops subscriptions. + public func dispose() { + for unsubscribe in unsubscribers { unsubscribe() } + unsubscribers.removeAll() + runtime.dispose() + } +} + +private struct FormNameKey: EnvironmentKey { + static let defaultValue: String? = nil +} + +extension EnvironmentValues { + /// The enclosing form's name; form fields store their values under it. + public var openUIFormName: String? { + get { self[FormNameKey.self] } + set { self[FormNameKey.self] = newValue } + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUINode.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUINode.swift new file mode 100644 index 0000000000..a1e99d03aa --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUINode.swift @@ -0,0 +1,85 @@ +import OpenUILang +import SwiftUI + +/// Renders any prop value: an element through its library component, an array +/// as a stack of nodes, scalars as text, and nothing for null. +public struct OpenUINode: View { + public let value: OpenUIValue + + public init(_ value: OpenUIValue) { + self.value = value + } + + public var body: some View { + switch value { + case .element(let element): + OpenUIElementView(element: element) + case .array(let items): + OpenUINodes(items) + case .string, .number, .bool: + Text(displayText(value)) + default: + EmptyView() + } + } +} + +/// Renders a list of nodes in a vertical stack. Each node keeps its identity +/// across streamed updates (by statement name, else position), so inputs keep +/// focus and local state while the response re-renders. +public struct OpenUINodes: View { + let items: [NodeItem] + let spacing: CGFloat? + let alignment: HorizontalAlignment + + public init( + _ values: [OpenUIValue], spacing: CGFloat? = OpenUITheme.default.spacing, + alignment: HorizontalAlignment = .leading + ) { + self.items = NodeItem.list(values) + self.spacing = spacing + self.alignment = alignment + } + + public var body: some View { + VStack(alignment: alignment, spacing: spacing) { + ForEach(items) { item in + OpenUINode(item.value) + } + } + } +} + +/// A node with a stable identity for `ForEach`. +struct NodeItem: Identifiable { + let id: String + let value: OpenUIValue + + static func list(_ values: [OpenUIValue]) -> [NodeItem] { + var seen: [String: Int] = [:] + return values.enumerated().compactMap { index, value in + if value.isNullish { return nil } + var id = value.elementValue?.statementId ?? "#\(index)" + // A statement referenced twice in one list still needs unique ids. + if let count = seen[id] { + seen[id] = count + 1 + id += "~\(count)" + } else { + seen[id] = 1 + } + return NodeItem(id: id, value: value) + } + } +} + +/// Renders an element with its library component; unknown components render nothing. +struct OpenUIElementView: View { + let element: ElementNode + @Environment(OpenUIContext.self) private var context + + var body: some View { + if let component = context.library.component(named: element.typeName) { + component.content(ComponentProps(element)) + } + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift new file mode 100644 index 0000000000..21823fa3c9 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift @@ -0,0 +1,69 @@ +import OpenUILang +import SwiftUI + +/// Renders an OpenUI Lang response with a component library, updating as the +/// response streams in. +/// +/// ```swift +/// OpenUIRenderer(response: text, isStreaming: isStreaming, library: OpenUIChatLibrary.library) { +/// event in send(event.humanFriendlyMessage) +/// } +/// ``` +public struct OpenUIRenderer: View { + let response: String? + let isStreaming: Bool + let onAction: ((ActionEvent) -> Void)? + let onStateUpdate: ((OpenUIObject) -> Void)? + + @State private var context: OpenUIContext + + /// - Parameters: + /// - response: The response text so far. + /// - isStreaming: Whether more text is still arriving. + /// - library: The components the response may use. Changing it requires a new view identity. + /// - initialState: Restored `$state` and form values, e.g. from a saved conversation. + /// - toolProvider: Handles `Query` and `Mutation` tool calls. + /// - onStateUpdate: Called when `$state` or form values change. + /// - onAction: Called for actions the host handles (continue the conversation, open a URL). + /// A trailing closure binds here. + public init( + response: String?, isStreaming: Bool = false, library: SwiftUILibrary, + initialState: OpenUIObject? = nil, toolProvider: (any ToolProvider)? = nil, + onAction: ((ActionEvent) -> Void)? = nil, + onStateUpdate: ((OpenUIObject) -> Void)? = nil + ) { + self.response = response + self.isStreaming = isStreaming + self.onAction = onAction + self.onStateUpdate = onStateUpdate + _context = State( + initialValue: OpenUIContext( + library: library, initialState: initialState, toolProvider: toolProvider)) + } + + public var body: some View { + let _ = syncHandlers() + Group { + if let root = context.root { + OpenUIElementView(element: root) + .opacity(context.isQueryLoading ? 0.7 : 1) + .animation(.easeInOut(duration: 0.2), value: context.isQueryLoading) + } + } + .environment(context) + .onChange(of: response, initial: true) { + context.update(response: response, isStreaming: isStreaming) + } + .onChange(of: isStreaming) { + context.update(response: response, isStreaming: isStreaming) + } + } + + /// Hands the latest closures to the context. They aren't observed, so this + /// never triggers another render. + private func syncHandlers() -> Bool { + context.onAction = onAction + context.onStateUpdate = onStateUpdate + return true + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift new file mode 100644 index 0000000000..2a6e6760c6 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift @@ -0,0 +1,190 @@ +import SwiftUI + +/// Text with inline markdown (bold, italic, code, links), falling back to the +/// raw string when it doesn't parse (e.g. half-streamed markup). +struct InlineMarkdown: View { + let source: String + + init(_ source: String) { + self.source = source + } + + var body: some View { + Text(Self.attributed(source)) + } + + static func attributed(_ source: String) -> AttributedString { + let options = AttributedString.MarkdownParsingOptions( + interpretedSyntax: .inlineOnlyPreservingWhitespace) + return (try? AttributedString(markdown: source, options: options)) ?? AttributedString(source) + } +} + +/// Block-level markdown: headings, bullet and numbered lists, quotes, code +/// fences, rules and paragraphs. Inline formatting uses `InlineMarkdown`. +struct MarkdownBlocks: View { + enum Block { + case heading(level: Int, text: String) + case bullet(String) + case numbered(String, String) + case quote(String) + case code(String) + case rule + case paragraph(String) + } + + let blocks: [Block] + + init(_ source: String) { + blocks = Self.parse(source) + } + + var body: some View { + VStack(alignment: .leading, spacing: 8) { + ForEach(Array(blocks.enumerated()), id: \.offset) { _, block in + view(for: block) + } + } + } + + @ViewBuilder + private func view(for block: Block) -> some View { + switch block { + case .heading(let level, let text): + InlineMarkdown(text).font( + level <= 1 ? .title2.bold() : level == 2 ? .title3.bold() : .headline) + case .bullet(let text): + HStack(alignment: .firstTextBaseline, spacing: 6) { + Text("•") + InlineMarkdown(text) + } + case .numbered(let marker, let text): + HStack(alignment: .firstTextBaseline, spacing: 6) { + Text(marker).monospacedDigit() + InlineMarkdown(text) + } + case .quote(let text): + InlineMarkdown(text) + .foregroundStyle(.secondary) + .padding(.leading, 10) + .overlay(alignment: .leading) { Rectangle().fill(.secondary.opacity(0.4)).frame(width: 3) } + case .code(let text): + Text(text).font(.system(.callout, design: .monospaced)) + case .rule: + Divider() + case .paragraph(let text): + InlineMarkdown(text) + } + } + + static func parse(_ source: String) -> [Block] { + var blocks: [Block] = [] + var paragraph: [String] = [] + var code: [String]? = nil + + func flushParagraph() { + if !paragraph.isEmpty { + blocks.append(.paragraph(paragraph.joined(separator: "\n"))) + paragraph = [] + } + } + + for rawLine in source.components(separatedBy: "\n") { + let line = rawLine.trimmingCharacters(in: .whitespaces) + if line.hasPrefix("```") { + if let lines = code { + blocks.append(.code(lines.joined(separator: "\n"))) + code = nil + } else { + flushParagraph() + code = [] + } + continue + } + if code != nil { + code!.append(rawLine) + continue + } + if line.isEmpty { + flushParagraph() + } else if let hashes = line.prefix(while: { $0 == "#" }).count as Int?, hashes > 0, + hashes <= 6, + line.dropFirst(hashes).first == " " + { + flushParagraph() + blocks.append(.heading(level: hashes, text: String(line.dropFirst(hashes + 1)))) + } else if line == "---" || line == "***" { + flushParagraph() + blocks.append(.rule) + } else if let first = line.first, "-*+".contains(first), line.dropFirst().first == " " { + flushParagraph() + blocks.append(.bullet(String(line.dropFirst(2)))) + } else if let dot = line.firstIndex(of: "."), line[..") { + flushParagraph() + blocks.append(.quote(String(line.dropFirst()).trimmingCharacters(in: .whitespaces))) + } else { + paragraph.append(line) + } + } + if let lines = code { blocks.append(.code(lines.joined(separator: "\n"))) } + flushParagraph() + return blocks + } +} + +/// Lays children out in rows, wrapping to the next row when one is full. +struct FlowLayout: Layout { + var spacing: CGFloat = 8 + + func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize { + let rows = arrange(subviews, width: proposal.width ?? .infinity) + let width = rows.map(\.width).max() ?? 0 + let height = rows.map(\.height).reduce(0, +) + spacing * CGFloat(max(rows.count - 1, 0)) + return CGSize(width: proposal.width ?? width, height: height) + } + + func placeSubviews( + in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout () + ) { + var y = bounds.minY + for row in arrange(subviews, width: bounds.width) { + var x = bounds.minX + for index in row.indices { + let size = subviews[index].sizeThatFits(.unspecified) + subviews[index].place(at: CGPoint(x: x, y: y), proposal: ProposedViewSize(size)) + x += size.width + spacing + } + y += row.height + spacing + } + } + + private struct Row { + var indices: [Int] = [] + var width: CGFloat = 0 + var height: CGFloat = 0 + } + + private func arrange(_ subviews: Subviews, width: CGFloat) -> [Row] { + var rows: [Row] = [] + var current = Row() + for index in subviews.indices { + let size = subviews[index].sizeThatFits(.unspecified) + let needed = current.indices.isEmpty ? size.width : current.width + spacing + size.width + if needed > width, !current.indices.isEmpty { + rows.append(current) + current = Row() + } + current.width = current.indices.isEmpty ? size.width : current.width + spacing + size.width + current.height = max(current.height, size.height) + current.indices.append(index) + } + if !current.indices.isEmpty { rows.append(current) } + return rows + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift new file mode 100644 index 0000000000..42a09f2fd2 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift @@ -0,0 +1,79 @@ +import SwiftUI + +/// Spacing, shapes and colors the built-in components use. Override parts of +/// it with `.environment(\.openUITheme, theme)`. +public struct OpenUITheme: Sendable { + public var spacing: CGFloat = 12 + public var compactSpacing: CGFloat = 6 + public var cornerRadius: CGFloat = 10 + public var smallCornerRadius: CGFloat = 6 + public var cardPadding: CGFloat = 16 + public var accent: Color = .accentColor + public var surface: Color = .platformSecondaryBackground + public var sunkSurface: Color = .platformTertiaryBackground + public var border: Color = .secondary.opacity(0.25) + public var chartHeight: CGFloat = 220 + + public init() {} + + public static let `default` = OpenUITheme() +} + +private struct ThemeKey: EnvironmentKey { + static let defaultValue = OpenUITheme.default +} + +extension EnvironmentValues { + public var openUITheme: OpenUITheme { + get { self[ThemeKey.self] } + set { self[ThemeKey.self] = newValue } + } +} + +extension Color { + static var platformSecondaryBackground: Color { + #if os(macOS) + Color(nsColor: .controlBackgroundColor) + #else + Color(uiColor: .secondarySystemBackground) + #endif + } + + /// A light recessed fill that works in light and dark mode on every platform. + static var platformTertiaryBackground: Color { Color.primary.opacity(0.06) } +} + +/// Status colors shared by callouts, tags and form errors. +func statusColor(_ variant: String?) -> Color { + switch variant { + case "info": return .blue + case "warning": return .orange + case "error", "danger": return .red + case "success": return .green + default: return .secondary + } +} + +/// The surface behind a "card" / "sunk" / "clear" container variant. +struct SurfaceModifier: ViewModifier { + let variant: String + @Environment(\.openUITheme) private var theme + + func body(content: Content) -> some View { + switch variant { + case "clear": + content + case "sunk": + content.padding(theme.cardPadding) + .background(theme.sunkSurface, in: RoundedRectangle(cornerRadius: theme.cornerRadius)) + default: + content.padding(theme.cardPadding) + .background(theme.surface, in: RoundedRectangle(cornerRadius: theme.cornerRadius)) + .overlay(RoundedRectangle(cornerRadius: theme.cornerRadius).strokeBorder(theme.border)) + } + } +} + +extension View { + func surface(_ variant: String) -> some View { modifier(SurfaceModifier(variant: variant)) } +} diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chat-examples.json b/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chat-examples.json new file mode 100644 index 0000000000..e860788f0f --- /dev/null +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chat-examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "chat-example-1", + "input": "Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }" + }, + { + "name": "chat-example-2", + "input": "Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")" + }, + { + "name": "chat-example-3", + "input": "Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)" + }, + { + "name": "chat-example-4", + "input": "Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }" + }, + { + "name": "chat-example-5", + "input": "Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")" + } +] diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift new file mode 100644 index 0000000000..73477004f6 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -0,0 +1,179 @@ +import Foundation +import SwiftUI +import Testing + +@testable import OpenUISwiftUI + +#if canImport(AppKit) + import AppKit +#endif + +@MainActor +@Suite struct ChatLibraryTests { + @Test func everyComponentHasAView() { + for schema in ChatComponents.all { + #expect( + OpenUIChatLibrary.views[schema.name] != nil + || OpenUIChatLibrary.dataOnly.contains(schema.name), + "\(schema.name) has no view") + } + #expect(OpenUIChatLibrary.library.rootName == "Card") + #expect(OpenUIChatLibrary.library.components.count == ChatComponents.all.count) + } +} + +@Suite struct CardActionTests { + let item: OpenUIObject = ["itemIndex": 1, "itemId": "a", "itemTitle": .undefined] + + @Test func noActionContinuesWithItemContext() { + #expect( + withItemContext(.null, item) + == ["type": "continue_conversation", "params": ["itemIndex": 1, "itemId": "a"]]) + } + + @Test func actionPlanAppendsSelectedItemToToAssistant() { + let plan = OpenUIValue.actionPlan( + ActionPlan(steps: [ + .continueConversation(message: "Go", context: "ctx"), + .continueConversation(message: "Bare", context: nil), + .openUrl(url: "https://openui.com"), + ])) + guard case .actionPlan(let merged) = withItemContext(plan, item) else { + Issue.record("expected an action plan") + return + } + let suffix = #"Selected item: {"itemIndex":1,"itemId":"a"}"# + #expect( + merged.steps == [ + .continueConversation(message: "Go", context: "ctx\n\(suffix)"), + .continueConversation(message: "Bare", context: suffix), + .openUrl(url: "https://openui.com"), + ]) + #expect(withItemContext(plan, [:]) == plan) + } + + @Test func legacyActionMergesParams() { + let legacy: OpenUIValue = [ + "type": "continue_conversation", "context": "Explore", "params": ["x": 1], + ] + #expect( + withItemContext(legacy, item) + == [ + "type": "continue_conversation", + "params": ["x": 1, "context": "Explore", "itemIndex": 1, "itemId": "a"], + ]) + } +} + +@Suite struct IconTests { + @Test func mapsLucideNamesWithFallbacks() { + #expect(LucideSymbols.systemName(for: "users", category: nil) == "person.2") + #expect( + LucideSymbols.systemName(for: "triangle-alert", category: nil) == "exclamationmark.triangle") + #expect(LucideSymbols.systemName(for: "no-such-icon", category: "finance") == "dollarsign") + #expect( + LucideSymbols.systemName(for: "no-such-icon", category: nil) + == LucideSymbols.symbols[LucideSymbols.defaultFallback]) + } + + @Test func categoryFallbacksResolve() { + for (category, name) in LucideSymbols.categoryFallbacks { + #expect(LucideSymbols.symbols[name] != nil, "\(category) → \(name)") + } + } + + #if canImport(AppKit) + @Test func everyMappedSymbolExists() { + for (name, symbol) in LucideSymbols.symbols { + #expect( + NSImage(systemSymbolName: symbol, accessibilityDescription: nil) != nil, + "\(name) → \(symbol)") + } + } + #endif +} + +@Suite struct NodeIdentityTests { + @Test func prefersStatementIdsAndStaysUnique() { + let element = { (id: String?) -> OpenUIValue in + .element(ElementNode(statementId: id, typeName: "TextContent", props: [:], partial: false)) + } + let items = NodeItem.list([element("a"), .null, element(nil), element("a"), "text"]) + #expect(items.map(\.id) == ["a", "#2", "a~1", "#4"]) + } +} + +@MainActor +@Suite struct OpenUIContextTests { + @Test func updatesAndRoutesActions() async { + let context = OpenUIContext(library: OpenUIChatLibrary.library) + var events: [ActionEvent] = [] + context.onAction = { events.append($0) } + let start = context.revision + + context.update( + response: "root = Card([FollowUpBlock([FollowUpItem(\"More\")])])", isStreaming: false) + #expect(context.revision > start) + #expect(context.root?.typeName == "Card") + + await context.runtime.triggerAction("More") + #expect(events.map(\.humanFriendlyMessage) == ["More"]) + + let before = context.revision + context.runtime.store.set("$x", 1) + #expect(context.revision > before) + } + + @Test func seedsDefaultsOnlyAfterStreaming() { + let context = OpenUIContext(library: OpenUIChatLibrary.library) + context.update(response: "root = Card([])", isStreaming: true) + context.setDefaultValue(form: "f", componentType: "Chips", name: "c", value: ["a"]) + #expect(context.fieldValue(form: "f", name: "c") == .undefined) + + context.update(response: "root = Card([])", isStreaming: false) + context.setDefaultValue(form: "f", componentType: "Chips", name: "c", value: ["a"]) + #expect(context.fieldValue(form: "f", name: "c") == ["a"]) + } +} + +#if canImport(AppKit) + /// Renders each chat library example end to end, offscreen, and checks it + /// produced a real layout (not an empty or collapsed view). + @MainActor + @Suite struct EndToEndRenderTests { + nonisolated static let examples: [(name: String, input: String)] = { + let url = Bundle.module.url( + forResource: "chat-examples", withExtension: "json", subdirectory: "Fixtures")! + let json = try! JSON.parse(String(contentsOf: url, encoding: .utf8)) + return (json.arrayValue ?? []).map { ($0["name"].stringValue!, $0["input"].stringValue!) } + }() + + @Test(arguments: examples.map(\.name)) + func rendersChatExample(_ name: String) { + let input = Self.examples.first { $0.name == name }!.input + let host = NSHostingView( + rootView: OpenUIRenderer(response: input, library: OpenUIChatLibrary.library) + .frame(width: 420)) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 420, height: 600), styleMask: [.borderless], + backing: .buffered, defer: false) + window.contentView = host + RunLoop.main.run(until: Date().addingTimeInterval(0.3)) + #expect(host.fittingSize.height > 200, "\(name) rendered \(host.fittingSize)") + } + } +#endif + +/// Libraries are typically global constants; this must compile under Swift 6. +let globalTestLibrary = SwiftUILibrary( + components: [ + SwiftUIComponent(ComponentSchema("Box", description: "", props: [Prop("text", .string)])) { + Text($0.text("text")) + } + ], root: "Box") + +@Suite struct GlobalLibraryTests { + @Test func globalLibraryIsUsable() { + #expect(globalTestLibrary.paramMap["Box"]?.map(\.name) == ["text"]) + } +} From 99c9d91d07a068e08042572f50f47472e3c710c9 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 00:43:36 +0530 Subject: [PATCH 06/52] feat(swift-lang): port mergeStatements and OpenUI Cloud's config block Edit mode's mergeStatements and generateSystemPrompt({ cloud: true }) (with the library checks Cloud applies) are now in OpenUILang, both checked against fixtures generated from lang-core. Library JSON Schemas now match Zod's key order exactly: top-level properties in library order, $defs in Zod's depth-first discovery order, and minItems before type. The chat schemas are listed in openuiChatLibrary's order, so the full chat library schema and its Cloud config are byte-identical to lang-core's output. --- .../swift-lang/Scripts/generate-fixtures.mjs | 155 ++- .../Sources/OpenUILang/ChatComponents.swift | 888 +++++++++--------- .../Sources/OpenUILang/CloudConfig.swift | 238 +++++ .../Sources/OpenUILang/Library.swift | 41 +- .../swift-lang/Sources/OpenUILang/Merge.swift | 136 +++ .../OpenUILangTests/ChatComponentsTests.swift | 13 +- .../OpenUILangTests/EditAndCloudTests.swift | 70 ++ .../Tests/OpenUILangTests/Fixtures/cloud.json | 379 ++++++++ .../Tests/OpenUILangTests/Fixtures/merge.json | 117 +++ .../OpenUILangTests/JSSemanticsTests.swift | 2 +- 10 files changed, 1589 insertions(+), 450 deletions(-) create mode 100644 packages/swift-lang/Sources/OpenUILang/CloudConfig.swift create mode 100644 packages/swift-lang/Sources/OpenUILang/Merge.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/EditAndCloudTests.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/Fixtures/cloud.json create mode 100644 packages/swift-lang/Tests/OpenUILangTests/Fixtures/merge.json diff --git a/packages/swift-lang/Scripts/generate-fixtures.mjs b/packages/swift-lang/Scripts/generate-fixtures.mjs index d23555e010..ab41336640 100644 --- a/packages/swift-lang/Scripts/generate-fixtures.mjs +++ b/packages/swift-lang/Scripts/generate-fixtures.mjs @@ -7,6 +7,7 @@ // Each fixture pairs an input with what @openuidev/lang-core produces for it. // The Swift tests feed the same input to the Swift port and compare. +import { createHash } from "node:crypto"; import { mkdirSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; @@ -446,6 +447,156 @@ const promptCases = [ const chatComponentSpecs = chatSpec; +// ── Edit mode ───────────────────────────────────────────────────────────── + +const base = [ + 'root = Card([title, body, $filter], "Report")', + 'title = TextContent("Q3", "large")', + "body = Table([colA, colB])", + 'colA = Col("Region", ["EU", "US"])', + 'colB = Col("Revenue", [1, 2])', + '$filter = "all"', +].join("\n"); + +const mergeCases = [ + { name: "empty-existing", existing: "", patch: 'root = Card([a])\na = TextContent("x")' }, + { name: "empty-patch", existing: base, patch: " \n" }, + { name: "replace", existing: base, patch: 'title = TextContent("Q4", "large")' }, + { + name: "add-referenced", + existing: base, + patch: 'root = Card([title, body, note])\nnote = Callout("info", "Hi")', + }, + { name: "add-unreferenced", existing: base, patch: 'orphan = TextContent("never shown")' }, + { name: "delete", existing: base, patch: "body = null\nroot = Card([title])" }, + { name: "gc-after-replace", existing: base, patch: 'body = TextContent("no table")' }, + { name: "keeps-unused-state", existing: base, patch: "root = Card([title])\n$extra = 1" }, + { name: "root-deleted", existing: base, patch: "root = null" }, + { name: "fenced-patch", existing: base, patch: '```openui\ntitle = TextContent("Fenced")\n```' }, + { + name: "multiline-and-strings", + existing: base, + patch: + 'body = Table([\n colA,\n colB\n])\ntitle = TextContent("a ) ] } \\" \' \\n", "large")', + }, + { name: "single-quotes", existing: base, patch: "title = TextContent('it\\'s (fine')" }, + { + name: "crlf", + existing: base.replaceAll("\n", "\r\n"), + patch: 'title = TextContent("CRLF")\r\n', + }, + { + name: "duplicate-existing", + existing: `${base}\ntitle = TextContent("dup")`, + patch: 'colA = Col("Area", [])', + }, + { name: "delete-then-add", existing: base, patch: 'title = null\ntitle = TextContent("back")' }, + { + name: "query-refs", + existing: + 'root = Card([t])\nt = Table([c])\nc = Col("n", q.rows)\nq = Query("list", {}, {rows: []})', + patch: 'c = Col("name", q.rows)', + }, + { + name: "custom-root", + existing: 'main = Card([a])\na = TextContent("x")\nb = TextContent("y")', + patch: 'a = TextContent("z")', + rootId: "main", + }, + { name: "unclosed-patch", existing: base, patch: 'title = TextContent("cut' }, + { + name: "chat-example", + existing: chatExamples[0].input, + patch: 'header = CardHeader("Edited", "by a patch")', + }, +].map((c) => ({ ...c, expected: core.mergeStatements(c.existing, c.patch, c.rootId) })); + +// ── Cloud config ────────────────────────────────────────────────────────── + +const cloudLibrary = { + root: "Card", + components: { Card: { signature: "Card(children: Text[])" } }, + componentGroups: [{ name: "Layout", components: ["Card", "Text"], notes: ["- Note"] }], + schema: { + $defs: { + Card: { + properties: { children: { type: "array", items: { $ref: "#/$defs/Text" } } }, + required: ["children"], + }, + Text: { properties: { value: { type: "string" } }, required: ["value"] }, + }, + }, +}; + +const brokenLibrary = { + root: "Missing", + components: {}, + componentGroups: [{ name: "G", components: ["Card", "Nope"] }, { name: 1 }], + schema: { + $defs: { + Card: { + properties: { + children: { type: "array", items: { $ref: "#/$defs/Gone" } }, + x: { $ref: "bad" }, + }, + required: ["children", "absent", 3], + }, + Text: { properties: [] }, + Bad: "nope", + }, + }, +}; + +function cloudCase(name, spec) { + try { + return { name, spec, expected: core.generateSystemPrompt({ cloud: true, ...spec }) }; + } catch (error) { + return { name, spec, error: error.message }; + } +} + +const cloudCases = [ + cloudCase("built-in", {}), + cloudCase("built-in-instructions", { instructions: "Answer in French." }), + cloudCase("built-in-empty-options", { promptOptions: { preamble: "" } }), + cloudCase("built-in-with-options", { promptOptions: { examples: [] } }), + cloudCase("library", { library: cloudLibrary }), + cloudCase("library-options", { + library: cloudLibrary, + promptOptions: { + preamble: "Be brief.", + additionalRules: ["One card"], + examples: ["a = 1"], + tools: ["x"], + editMode: true, + }, + instructions: "Extra.", + }), + cloudCase("library-empty-strings", { + library: cloudLibrary, + promptOptions: { preamble: "" }, + instructions: "", + }), + cloudCase("library-without-root", { + library: { ...cloudLibrary, root: undefined, componentGroups: undefined }, + }), + cloudCase("library-with-id", { library: { ...cloudLibrary, id: "lib-1" } }), + cloudCase("broken-library", { library: brokenLibrary }), + cloudCase("no-defs", { library: { components: {}, schema: { $defs: {} } } }), + cloudCase("no-schema", { library: { root: "", components: {} } }), +]; + +// The chat library's Cloud config is ~80 KB, so only its digest is stored. +const chatCloudConfig = core.generateSystemPrompt({ + cloud: true, + library: ui.openuiChatLibrary.toSpec(), + promptOptions: ui.openuiChatPromptOptions, +}); +const chatCloud = { + length: chatCloudConfig.length, + sha256: createHash("sha256").update(chatCloudConfig).digest("hex"), +}; + function write(name, data, indent = 1) { mkdirSync(fixtures, { recursive: true }); writeFileSync(join(fixtures, name), JSON.stringify(data, null, indent) + "\n"); @@ -457,6 +608,8 @@ write("streaming.json", streamingCases, 0); write("stream-set.json", setCases); write("evaluation.json", evalFixtures); write("prompts.json", promptCases); +write("merge.json", mergeCases); +write("cloud.json", { cases: cloudCases, chat: chatCloud }); // The chat examples, for the SwiftUI renderer's end-to-end render tests. mkdirSync(join(here, "..", "Tests", "OpenUISwiftUITests", "Fixtures"), { recursive: true }); @@ -471,5 +624,5 @@ writeFileSync( write("chat-spec.json", chatComponentSpecs); console.log( - `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set, ${evalFixtures.length} evaluation, ${promptCases.length} prompt fixtures`, + `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set, ${evalFixtures.length} evaluation, ${promptCases.length} prompt, ${mergeCases.length} merge, ${cloudCases.length} cloud fixtures`, ); diff --git a/packages/swift-lang/Sources/OpenUILang/ChatComponents.swift b/packages/swift-lang/Sources/OpenUILang/ChatComponents.swift index 41dd50b59f..479577c25c 100644 --- a/packages/swift-lang/Sources/OpenUILang/ChatComponents.swift +++ b/packages/swift-lang/Sources/OpenUILang/ChatComponents.swift @@ -40,6 +40,10 @@ public enum ChatComponents { ])), .optional), ]) + public static let cardHeader = ComponentSchema( + "CardHeader", description: "Header with optional title and subtitle", + props: [Prop("title", .string, .optional), Prop("subtitle", .string, .optional)]) + public static let textContent = ComponentSchema( "TextContent", description: @@ -58,10 +62,6 @@ public enum ChatComponents { Prop("variant", .enumeration(["clear", "card", "sunk"]), .optional), ]) - public static let cardHeader = ComponentSchema( - "CardHeader", description: "Header with optional title and subtitle", - props: [Prop("title", .string, .optional), Prop("subtitle", .string, .optional)]) - public static let callout = ComponentSchema( "Callout", description: @@ -80,10 +80,6 @@ public enum ChatComponents { Prop("title", .string, .optional), Prop("description", .string, .optional), ]) - public static let codeBlock = ComponentSchema( - "CodeBlock", description: "Syntax-highlighted code block", - props: [Prop("language", .string), Prop("codeString", .string)]) - public static let image = ComponentSchema( "Image", description: "Image with alt text and optional URL", props: [Prop("alt", .string), Prop("src", .string, .optional)]) @@ -104,6 +100,10 @@ public enum ChatComponents { ]))) ]) + public static let codeBlock = ComponentSchema( + "CodeBlock", description: "Syntax-highlighted code block", + props: [Prop("language", .string), Prop("codeString", .string)]) + public static let separator = ComponentSchema( "Separator", description: "Visual divider between content sections", props: [ @@ -111,18 +111,46 @@ public enum ChatComponents { Prop("decorative", .boolean, .optional), ]) - public static let horizontalBarChart = ComponentSchema( - "HorizontalBarChart", - description: "Horizontal bars; prefer when category labels are long or for ranked lists", + public static let table = ComponentSchema( + "Table", description: "Data table — column-oriented. Each Col holds its own data array.", + props: [Prop("columns", .array(.component("Col")))]) + + public static let col = ComponentSchema( + "Col", description: "Column definition — holds label + data array", + props: [ + Prop("label", .string), Prop("data", .any), + Prop("type", .enumeration(["string", "number", "action"]), .optional), + ]) + + public static let barChart = ComponentSchema( + "BarChart", + description: + "Vertical bars; use for comparing values across categories with one or more series", props: [ Prop("labels", .array(.string)), Prop("series", .array(.component("Series"))), Prop("variant", .enumeration(["grouped", "stacked"]), .optional), Prop("xLabel", .string, .optional), Prop("yLabel", .string, .optional), + Prop("height", .number, .optional), ]) - public static let series = ComponentSchema( - "Series", description: "One data series", - props: [Prop("category", .string), Prop("values", .array(.number))]) + public static let lineChart = ComponentSchema( + "LineChart", description: "Lines over categories; use for trends and continuous data over time", + props: [ + Prop("labels", .array(.string)), Prop("series", .array(.component("Series"))), + Prop("variant", .enumeration(["linear", "natural", "step"]), .optional), + Prop("xLabel", .string, .optional), Prop("yLabel", .string, .optional), + Prop("height", .number, .optional), + ]) + + public static let areaChart = ComponentSchema( + "AreaChart", + description: "Filled area under lines; use for cumulative totals or volume trends over time", + props: [ + Prop("labels", .array(.string)), Prop("series", .array(.component("Series"))), + Prop("variant", .enumeration(["linear", "natural", "step"]), .optional), + Prop("xLabel", .string, .optional), Prop("yLabel", .string, .optional), + Prop("height", .number, .optional), + ]) public static let radarChart = ComponentSchema( "RadarChart", @@ -130,6 +158,19 @@ public enum ChatComponents { "Spider/web chart; use for comparing multiple variables across one or more entities", props: [Prop("labels", .array(.string)), Prop("series", .array(.component("Series")))]) + public static let horizontalBarChart = ComponentSchema( + "HorizontalBarChart", + description: "Horizontal bars; prefer when category labels are long or for ranked lists", + props: [ + Prop("labels", .array(.string)), Prop("series", .array(.component("Series"))), + Prop("variant", .enumeration(["grouped", "stacked"]), .optional), + Prop("xLabel", .string, .optional), Prop("yLabel", .string, .optional), + ]) + + public static let series = ComponentSchema( + "Series", description: "One data series", + props: [Prop("category", .string), Prop("values", .array(.number))]) + public static let pieChart = ComponentSchema( "PieChart", description: "Circular slices; use plucked arrays: PieChart(data.categories, data.values)", @@ -150,6 +191,10 @@ public enum ChatComponents { "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)", props: [Prop("labels", .array(.string)), Prop("values", .array(.number))]) + public static let slice = ComponentSchema( + "Slice", description: "One slice with label and numeric value", + props: [Prop("category", .string), Prop("value", .number)]) + public static let scatterChart = ComponentSchema( "ScatterChart", description: "X/Y scatter plot; use for correlations, distributions, and clustering", @@ -166,53 +211,6 @@ public enum ChatComponents { "Point", description: "Data point with numeric coordinates", props: [Prop("x", .number), Prop("y", .number), Prop("z", .number, .optional)]) - public static let areaChart = ComponentSchema( - "AreaChart", - description: "Filled area under lines; use for cumulative totals or volume trends over time", - props: [ - Prop("labels", .array(.string)), Prop("series", .array(.component("Series"))), - Prop("variant", .enumeration(["linear", "natural", "step"]), .optional), - Prop("xLabel", .string, .optional), Prop("yLabel", .string, .optional), - Prop("height", .number, .optional), - ]) - - public static let barChart = ComponentSchema( - "BarChart", - description: - "Vertical bars; use for comparing values across categories with one or more series", - props: [ - Prop("labels", .array(.string)), Prop("series", .array(.component("Series"))), - Prop("variant", .enumeration(["grouped", "stacked"]), .optional), - Prop("xLabel", .string, .optional), Prop("yLabel", .string, .optional), - Prop("height", .number, .optional), - ]) - - public static let lineChart = ComponentSchema( - "LineChart", description: "Lines over categories; use for trends and continuous data over time", - props: [ - Prop("labels", .array(.string)), Prop("series", .array(.component("Series"))), - Prop("variant", .enumeration(["linear", "natural", "step"]), .optional), - Prop("xLabel", .string, .optional), Prop("yLabel", .string, .optional), - Prop("height", .number, .optional), - ]) - - public static let table = ComponentSchema( - "Table", description: "Data table — column-oriented. Each Col holds its own data array.", - props: [Prop("columns", .array(.component("Col")))]) - - public static let col = ComponentSchema( - "Col", description: "Column definition — holds label + data array", - props: [ - Prop("label", .string), Prop("data", .any), - Prop("type", .enumeration(["string", "number", "action"]), .optional), - ]) - - public static let tagBlock = ComponentSchema( - "TagBlock", description: "tags is an array of strings; optional size sm | md | lg", - props: [ - Prop("tags", .array(.string)), Prop("size", .enumeration(["sm", "md", "lg"]), .optional), - ]) - public static let form = ComponentSchema( "Form", description: "Form container with fields and explicit action buttons", props: [ @@ -220,23 +218,6 @@ public enum ChatComponents { Prop("fields", .array(.component("FormControl")), .defaulted([])), ]) - public static let buttons = ComponentSchema( - "Buttons", - description: "Group of Button components. direction: \"row\" (default) | \"column\".", - props: [ - Prop("buttons", .array(.component("Button"))), - Prop("direction", .enumeration(["row", "column"]), .optional), - ]) - - public static let button = ComponentSchema( - "Button", description: "Clickable button", - props: [ - Prop("label", .string), Prop("action", .actionExpression, .optional), - Prop("variant", .enumeration(["primary", "secondary", "tertiary"]), .optional), - Prop("type", .enumeration(["normal", "destructive"]), .optional), - Prop("size", .enumeration(["extra-small", "small", "medium", "large"]), .optional), - ]) - public static let formControl = ComponentSchema( "FormControl", description: "Field with label, input component, and optional hint text", props: [ @@ -250,6 +231,10 @@ public enum ChatComponents { ])), Prop("hint", .string, .optional), ]) + public static let label = ComponentSchema( + "Label", description: "Text label", + props: [Prop("text", .string)]) + public static let input = ComponentSchema( "Input", description: "", props: [ @@ -323,93 +308,218 @@ public enum ChatComponents { "RadioItem", description: "", props: [Prop("label", .string), Prop("description", .string), Prop("value", .string)]) - public static let chips = ComponentSchema( - "Chips", - description: - "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.", + public static let switchGroup = ComponentSchema( + "SwitchGroup", description: "Group of switch toggles", props: [ - Prop("name", .string), - Prop("type", .enumeration(["single", "multiple"]), .defaulted("multiple")), - Prop("items", .array(.component("ChipItem")), .defaulted([])), - Prop("rules", formRules, .optional), - Prop("defaultValue", .union([.string, .array(.string)]), .optional), + Prop("name", .string), Prop("items", .array(.component("SwitchItem"))), + Prop("variant", .enumeration(["clear", "card", "sunk"]), .optional), + Prop("value", .record(.boolean), .optional, binding: true), ]) - public static let chipItem = ComponentSchema( - "ChipItem", - description: - "A single selectable chip inside a Chips group, with a value, label and optional icon.", + public static let switchItem = ComponentSchema( + "SwitchItem", description: "Individual switch toggle", props: [ - Prop("value", .string), Prop("label", .string), Prop("icon", .component("Icon"), .optional), - Prop("disabled", .boolean, .optional), + Prop("label", .string, .optional), Prop("description", .string, .optional), + Prop("name", .string), Prop("defaultChecked", .boolean, .optional), ]) - public static let icon = ComponentSchema( - "Icon", - description: - "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.", - props: [Prop("name", .string), Prop("category", .string, .optional)]) + public static let button = ComponentSchema( + "Button", description: "Clickable button", + props: [ + Prop("label", .string), Prop("action", .actionExpression, .optional), + Prop("variant", .enumeration(["primary", "secondary", "tertiary"]), .optional), + Prop("type", .enumeration(["normal", "destructive"]), .optional), + Prop("size", .enumeration(["extra-small", "small", "medium", "large"]), .optional), + ]) - public static let optionCards = ComponentSchema( - "OptionCards", - description: - "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.", + public static let buttons = ComponentSchema( + "Buttons", + description: "Group of Button components. direction: \"row\" (default) | \"column\".", props: [ - Prop("name", .string), - Prop("type", .enumeration(["single", "multiple"]), .defaulted("single")), - Prop("items", .array(.component("OptionCard")), .defaulted([])), - Prop("rules", formRules, .optional), - Prop("defaultValue", .union([.string, .array(.string)]), .optional), + Prop("buttons", .array(.component("Button"))), + Prop("direction", .enumeration(["row", "column"]), .optional), ]) - public static let optionCard = ComponentSchema( - "OptionCard", + public static let listBlock = ComponentSchema( + "ListBlock", description: - "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.", + "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.", props: [ - Prop("value", .string), Prop("title", .string), Prop("subtitle", .string, .optional), - Prop("topContent", .union([.component("Icon"), .component("Image")]), .optional), - Prop("disabled", .boolean, .optional), + Prop("items", .array(.component("ListItem"))), + Prop("variant", .enumeration(["number", "image"]), .optional), + Prop("size", .enumeration(["default", "small"]), .optional), ]) - public static let iconButton = ComponentSchema( - "IconButton", + public static let listItem = ComponentSchema( + "ListItem", description: - "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.", + "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.", props: [ - Prop("name", .string), Prop("icon", .component("Icon")), - Prop("action", .actionExpression, .optional), - Prop("variant", .enumeration(["primary", "secondary", "tertiary"]), .optional), - Prop("size", .enumeration(["extra-small", "small", "medium", "large"]), .optional), - Prop("shape", .enumeration(["square", "circle"]), .optional), + Prop("title", .string), Prop("subtitle", .string, .optional), + Prop("image", .object([Prop("src", .string), Prop("alt", .string)]), .optional), + Prop("actionLabel", .string, .optional), Prop("action", .actionExpression, .optional), ]) - public static let steps = ComponentSchema( - "Steps", description: "Step-by-step guide", - props: [Prop("items", .array(.component("StepsItem")))]) + public static let followUpBlock = ComponentSchema( + "FollowUpBlock", + description: "List of clickable follow-up suggestions placed at the end of a response", + props: [Prop("items", .array(.component("FollowUpItem")))]) - public static let stepsItem = ComponentSchema( - "StepsItem", description: "title and details text for one step", - props: [Prop("title", .string), Prop("details", .string)]) + public static let followUpItem = ComponentSchema( + "FollowUpItem", + description: "Clickable follow-up suggestion — when clicked, sends text as user message", + props: [Prop("text", .string)]) - public static let inlineHeader = ComponentSchema( - "InlineHeader", + public static let sectionBlock = ComponentSchema( + "SectionBlock", description: - "Compact section heading with an optional one-line description, for use inside cards.", - props: [Prop("heading", .string), Prop("description", .string, .optional)]) + "Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section.", + props: [ + Prop("sections", .array(.component("SectionItem"))), Prop("isFoldable", .boolean, .optional), + ]) - public static let entityList = ComponentSchema( - "EntityList", - description: - "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.", + public static let sectionItem = ComponentSchema( + "SectionItem", + description: "Section with a label and collapsible content — used inside SectionBlock", props: [ + Prop("value", .string), Prop("trigger", .string), Prop( - "rows", + "content", .array( - .object([ - Prop("left", .string), Prop("right", .string), - Prop("rightVariant", .enumeration(["text", "number"]), .defaulted("text")), - ])), .defaulted([])), + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), + .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), + .component("LineChart"), .component("Table"), .component("TagBlock"), + .component("Form"), .component("Buttons"), .component("IconButton"), + .component("Steps"), .component("InlineHeader"), .component("EntityList"), + .component("EditableTable"), .component("SnippetCardBlock"), + .component("OverviewCardBlock"), .component("ContextCardBlock"), + .component("CompositeCardBlock"), .component("VisualCardBlock"), + .component("ListBlock"), .component("FollowUpBlock"), .component("Tabs"), + .component("Accordion"), + ]))), + ]) + + public static let tabs = ComponentSchema( + "Tabs", description: "Tabbed container", + props: [Prop("items", .array(.component("TabItem")))]) + + public static let tabItem = ComponentSchema( + "TabItem", + description: "value is unique id, trigger is tab label, content is array of components", + props: [ + Prop("value", .string), Prop("trigger", .string), + Prop( + "content", + .array( + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), + .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), + .component("LineChart"), .component("Table"), .component("TagBlock"), + .component("Form"), .component("Buttons"), .component("IconButton"), + .component("Steps"), .component("InlineHeader"), .component("EntityList"), + .component("EditableTable"), .component("SnippetCardBlock"), + .component("OverviewCardBlock"), .component("ContextCardBlock"), + .component("CompositeCardBlock"), .component("VisualCardBlock"), + .component("ListBlock"), .component("FollowUpBlock"), .component("Accordion"), + ]))), + ]) + + public static let accordion = ComponentSchema( + "Accordion", description: "Collapsible sections", + props: [Prop("items", .array(.component("AccordionItem")))]) + + public static let accordionItem = ComponentSchema( + "AccordionItem", description: "value is unique id, trigger is section title", + props: [ + Prop("value", .string), Prop("trigger", .string), + Prop( + "content", + .array( + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), + .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), + .component("LineChart"), .component("Table"), .component("TagBlock"), + .component("Form"), .component("Buttons"), .component("IconButton"), + .component("Steps"), .component("InlineHeader"), .component("EntityList"), + .component("EditableTable"), .component("SnippetCardBlock"), + .component("OverviewCardBlock"), .component("ContextCardBlock"), + .component("CompositeCardBlock"), .component("VisualCardBlock"), + .component("ListBlock"), .component("FollowUpBlock"), + ]))), + ]) + + public static let steps = ComponentSchema( + "Steps", description: "Step-by-step guide", + props: [Prop("items", .array(.component("StepsItem")))]) + + public static let stepsItem = ComponentSchema( + "StepsItem", description: "title and details text for one step", + props: [Prop("title", .string), Prop("details", .string)]) + + public static let carousel = ComponentSchema( + "Carousel", description: "Horizontal scrollable carousel", + props: [ + Prop( + "children", + .array( + .array( + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), + .component("SingleStackedBarChart"), .component("ScatterChart"), + .component("AreaChart"), .component("BarChart"), .component("LineChart"), + .component("Table"), .component("TagBlock"), .component("Form"), + .component("Buttons"), .component("IconButton"), .component("Steps"), + .component("InlineHeader"), .component("EntityList"), .component("EditableTable"), + .component("SnippetCardBlock"), .component("OverviewCardBlock"), + .component("ContextCardBlock"), .component("CompositeCardBlock"), + .component("VisualCardBlock"), .component("ListBlock"), .component("FollowUpBlock"), + ])))), Prop("variant", .enumeration(["card", "sunk"]), .optional), + ]) + + public static let tagBlock = ComponentSchema( + "TagBlock", description: "tags is an array of strings; optional size sm | md | lg", + props: [ + Prop("tags", .array(.string)), Prop("size", .enumeration(["sm", "md", "lg"]), .optional), + ]) + + public static let tag = ComponentSchema( + "Tag", description: "Styled tag/badge with optional Icon and variant", + props: [ + Prop("text", .string), Prop("icon", .component("Icon"), .optional), + Prop("size", .enumeration(["sm", "md", "lg"]), .optional), + Prop( + "variant", .enumeration(["neutral", "info", "success", "warning", "danger"]), .optional), + ]) + + public static let entityList = ComponentSchema( + "EntityList", + description: + "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.", + props: [ + Prop( + "rows", + .array( + .object([ + Prop("left", .string), Prop("right", .string), + Prop("rightVariant", .enumeration(["text", "number"]), .defaulted("text")), + ])), .defaulted([])), Prop("size", .enumeration(["small", "default"]), .defaulted("default")), Prop( "header", @@ -425,6 +535,30 @@ public enum ChatComponents { ]), .optional), ]) + public static let inlineHeader = ComponentSchema( + "InlineHeader", + description: + "Compact section heading with an optional one-line description, for use inside cards.", + props: [Prop("heading", .string), Prop("description", .string, .optional)]) + + public static let icon = ComponentSchema( + "Icon", + description: + "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.", + props: [Prop("name", .string), Prop("category", .string, .optional)]) + + public static let iconButton = ComponentSchema( + "IconButton", + description: + "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.", + props: [ + Prop("name", .string), Prop("icon", .component("Icon")), + Prop("action", .actionExpression, .optional), + Prop("variant", .enumeration(["primary", "secondary", "tertiary"]), .optional), + Prop("size", .enumeration(["extra-small", "small", "medium", "large"]), .optional), + Prop("shape", .enumeration(["square", "circle"]), .optional), + ]) + public static let editableTable = ComponentSchema( "EditableTable", description: @@ -449,25 +583,69 @@ public enum ChatComponents { .defaulted([])), ]) - public static let snippetCardBlock = ComponentSchema( - "SnippetCardBlock", + public static let chipItem = ComponentSchema( + "ChipItem", description: - "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.", + "A single selectable chip inside a Chips group, with a value, label and optional icon.", props: [ - Prop("items", .array(.component("SnippetCardItem"), minItems: 2)), - Prop("layout", .enumeration(["grid"]), .defaulted("grid")), - Prop("responsive", .boolean, .defaulted(true)), Prop("action", .actionExpression, .optional), - Prop("gap", .union([.number, .string]), .optional), + Prop("value", .string), Prop("label", .string), Prop("icon", .component("Icon"), .optional), + Prop("disabled", .boolean, .optional), ]) - public static let snippetCardItem = ComponentSchema( - "SnippetCardItem", + public static let chips = ComponentSchema( + "Chips", description: - "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).", + "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.", props: [ - Prop("id", .string, .optional), - Prop("lhs", .union([.component("IconText"), .component("ImageText")])), - Prop("rhs", .union([.component("Text"), .component("BoldText")]), .optional), + Prop("name", .string), + Prop("type", .enumeration(["single", "multiple"]), .defaulted("multiple")), + Prop("items", .array(.component("ChipItem")), .defaulted([])), + Prop("rules", formRules, .optional), + Prop("defaultValue", .union([.string, .array(.string)]), .optional), + ]) + + public static let optionCard = ComponentSchema( + "OptionCard", + description: + "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.", + props: [ + Prop("value", .string), Prop("title", .string), Prop("subtitle", .string, .optional), + Prop("topContent", .union([.component("Icon"), .component("Image")]), .optional), + Prop("disabled", .boolean, .optional), + ]) + + public static let optionCards = ComponentSchema( + "OptionCards", + description: + "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.", + props: [ + Prop("name", .string), + Prop("type", .enumeration(["single", "multiple"]), .defaulted("single")), + Prop("items", .array(.component("OptionCard")), .defaulted([])), + Prop("rules", formRules, .optional), + Prop("defaultValue", .union([.string, .array(.string)]), .optional), + ]) + + public static let text = ComponentSchema( + "Text", + description: + "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.", + props: [ + Prop("variant", .enumeration(["text", "number"]), .defaulted("text")), Prop("value", .string), + Prop("subtext", .string, .optional), + Prop("subtextVariant", .enumeration(["text", "number", "metric"]), .defaulted("text")), + Prop("size", .enumeration(["xs", "sm", "md", "lg"]), .defaulted("sm")), + ]) + + public static let boldText = ComponentSchema( + "BoldText", + description: + "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.", + props: [ + Prop("variant", .enumeration(["text", "number"]), .defaulted("text")), Prop("value", .string), + Prop("subtext", .string, .optional), + Prop("subtextVariant", .enumeration(["text", "number", "metric"]), .defaulted("text")), + Prop("size", .enumeration(["xs", "sm", "md", "lg"]), .defaulted("sm")), ]) public static let iconText = ComponentSchema( @@ -499,35 +677,57 @@ public enum ChatComponents { Prop("imageSize", .number, .optional), ]) - public static let text = ComponentSchema( - "Text", + public static let imageTextLarge = ComponentSchema( + "ImageTextLarge", description: - "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.", + "A full-width banner image above a bold title and optional subtitle. src must be a real image URL.", props: [ - Prop("variant", .enumeration(["text", "number"]), .defaulted("text")), Prop("value", .string), - Prop("subtext", .string, .optional), - Prop("subtextVariant", .enumeration(["text", "number", "metric"]), .defaulted("text")), - Prop("size", .enumeration(["xs", "sm", "md", "lg"]), .defaulted("sm")), + Prop("src", .string), Prop("alt", .string, .optional), Prop("title", .string), + Prop("subtitle", .string, .optional), Prop("bold", .boolean, .defaulted(false)), ]) - public static let boldText = ComponentSchema( - "BoldText", + public static let metricIndicatorInline = ComponentSchema( + "MetricIndicatorInline", description: - "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.", + "Headline metric value with an optional +/- percentage trend and subtext, all on one line.", props: [ - Prop("variant", .enumeration(["text", "number"]), .defaulted("text")), Prop("value", .string), - Prop("subtext", .string, .optional), - Prop("subtextVariant", .enumeration(["text", "number", "metric"]), .defaulted("text")), - Prop("size", .enumeration(["xs", "sm", "md", "lg"]), .defaulted("sm")), + Prop("value", .string), Prop("subtext", .string, .optional), + Prop( + "trend", + .object([Prop("direction", .enumeration(["up", "down"])), Prop("value", .number)]), + .optional), ]) - public static let overviewCardBlock = ComponentSchema( - "OverviewCardBlock", + public static let metricIndicatorWithStrikethrough = ComponentSchema( + "MetricIndicatorWithStrikethrough", description: - "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.", + "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.", props: [ - Prop("items", .array(.component("OverviewCardItem"), minItems: 2)), - Prop("layout", .enumeration(["grid", "carousel"]), .defaulted("grid")), + Prop("value", .string), Prop("subtext", .string, .optional), + Prop("previousValue", .string, .optional), + Prop( + "trend", + .object([Prop("direction", .enumeration(["up", "down"])), Prop("value", .number)]), + .optional), + ]) + + public static let snippetCardItem = ComponentSchema( + "SnippetCardItem", + description: + "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).", + props: [ + Prop("id", .string, .optional), + Prop("lhs", .union([.component("IconText"), .component("ImageText")])), + Prop("rhs", .union([.component("Text"), .component("BoldText")]), .optional), + ]) + + public static let snippetCardBlock = ComponentSchema( + "SnippetCardBlock", + description: + "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.", + props: [ + Prop("items", .array(.component("SnippetCardItem"), minItems: 2)), + Prop("layout", .enumeration(["grid"]), .defaulted("grid")), Prop("responsive", .boolean, .defaulted(true)), Prop("action", .actionExpression, .optional), Prop("gap", .union([.number, .string]), .optional), ]) @@ -542,24 +742,12 @@ public enum ChatComponents { Prop("bottom", .component("MetricIndicatorInline"), .optional), ]) - public static let metricIndicatorInline = ComponentSchema( - "MetricIndicatorInline", - description: - "Headline metric value with an optional +/- percentage trend and subtext, all on one line.", - props: [ - Prop("value", .string), Prop("subtext", .string, .optional), - Prop( - "trend", - .object([Prop("direction", .enumeration(["up", "down"])), Prop("value", .number)]), - .optional), - ]) - - public static let contextCardBlock = ComponentSchema( - "ContextCardBlock", + public static let overviewCardBlock = ComponentSchema( + "OverviewCardBlock", description: - "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.", + "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.", props: [ - Prop("items", .array(.component("ContextCardItem"), minItems: 2)), + Prop("items", .array(.component("OverviewCardItem"), minItems: 2)), Prop("layout", .enumeration(["grid", "carousel"]), .defaulted("grid")), Prop("responsive", .boolean, .defaulted(true)), Prop("action", .actionExpression, .optional), Prop("gap", .union([.number, .string]), .optional), @@ -575,21 +763,12 @@ public enum ChatComponents { Prop("bgImageSrc", .string, .optional), Prop("bgImageAlt", .string, .optional), ]) - public static let tag = ComponentSchema( - "Tag", description: "Styled tag/badge with optional Icon and variant", - props: [ - Prop("text", .string), Prop("icon", .component("Icon"), .optional), - Prop("size", .enumeration(["sm", "md", "lg"]), .optional), - Prop( - "variant", .enumeration(["neutral", "info", "success", "warning", "danger"]), .optional), - ]) - - public static let compositeCardBlock = ComponentSchema( - "CompositeCardBlock", + public static let contextCardBlock = ComponentSchema( + "ContextCardBlock", description: - "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.", + "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.", props: [ - Prop("items", .array(.component("CompositeCardItem"), minItems: 2)), + Prop("items", .array(.component("ContextCardItem"), minItems: 2)), Prop("layout", .enumeration(["grid", "carousel"]), .defaulted("grid")), Prop("responsive", .boolean, .defaulted(true)), Prop("action", .actionExpression, .optional), Prop("gap", .union([.number, .string]), .optional), @@ -615,65 +794,23 @@ public enum ChatComponents { .component("IconText"), .component("Image"), .component("AreaChart"), .component("BarChart"), .component("LineChart"), .component("ListBlock"), .component("TagBlock"), .component("EntityList"), - ])), .defaulted([])), - Prop( - "footer", - .object([ - Prop( - "price", - .union([.component("BoldText"), .component("MetricIndicatorWithStrikethrough")]), - .optional), Prop("button", .component("Button"), .optional), - ]), .optional), - ]) - - public static let imageTextLarge = ComponentSchema( - "ImageTextLarge", - description: - "A full-width banner image above a bold title and optional subtitle. src must be a real image URL.", - props: [ - Prop("src", .string), Prop("alt", .string, .optional), Prop("title", .string), - Prop("subtitle", .string, .optional), Prop("bold", .boolean, .defaulted(false)), - ]) - - public static let listBlock = ComponentSchema( - "ListBlock", - description: - "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.", - props: [ - Prop("items", .array(.component("ListItem"))), - Prop("variant", .enumeration(["number", "image"]), .optional), - Prop("size", .enumeration(["default", "small"]), .optional), - ]) - - public static let listItem = ComponentSchema( - "ListItem", - description: - "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.", - props: [ - Prop("title", .string), Prop("subtitle", .string, .optional), - Prop("image", .object([Prop("src", .string), Prop("alt", .string)]), .optional), - Prop("actionLabel", .string, .optional), Prop("action", .actionExpression, .optional), - ]) - - public static let metricIndicatorWithStrikethrough = ComponentSchema( - "MetricIndicatorWithStrikethrough", - description: - "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.", - props: [ - Prop("value", .string), Prop("subtext", .string, .optional), - Prop("previousValue", .string, .optional), - Prop( - "trend", - .object([Prop("direction", .enumeration(["up", "down"])), Prop("value", .number)]), - .optional), + ])), .defaulted([])), + Prop( + "footer", + .object([ + Prop( + "price", + .union([.component("BoldText"), .component("MetricIndicatorWithStrikethrough")]), + .optional), Prop("button", .component("Button"), .optional), + ]), .optional), ]) - public static let visualCardBlock = ComponentSchema( - "VisualCardBlock", + public static let compositeCardBlock = ComponentSchema( + "CompositeCardBlock", description: - "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.", + "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.", props: [ - Prop("items", .array(.component("VisualCardItem"), minItems: 2)), + Prop("items", .array(.component("CompositeCardItem"), minItems: 2)), Prop("layout", .enumeration(["grid", "carousel"]), .defaulted("grid")), Prop("responsive", .boolean, .defaulted(true)), Prop("action", .actionExpression, .optional), Prop("gap", .union([.number, .string]), .optional), @@ -689,152 +826,15 @@ public enum ChatComponents { Prop("bgImageAlt", .string, .optional), ]) - public static let followUpBlock = ComponentSchema( - "FollowUpBlock", - description: "List of clickable follow-up suggestions placed at the end of a response", - props: [Prop("items", .array(.component("FollowUpItem")))]) - - public static let followUpItem = ComponentSchema( - "FollowUpItem", - description: "Clickable follow-up suggestion — when clicked, sends text as user message", - props: [Prop("text", .string)]) - - public static let sectionBlock = ComponentSchema( - "SectionBlock", + public static let visualCardBlock = ComponentSchema( + "VisualCardBlock", description: - "Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section.", - props: [ - Prop("sections", .array(.component("SectionItem"))), Prop("isFoldable", .boolean, .optional), - ]) - - public static let sectionItem = ComponentSchema( - "SectionItem", - description: "Section with a label and collapsible content — used inside SectionBlock", - props: [ - Prop("value", .string), Prop("trigger", .string), - Prop( - "content", - .array( - .union([ - .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), - .component("Callout"), .component("TextCallout"), .component("CodeBlock"), - .component("Image"), .component("ImageBlock"), .component("ImageGallery"), - .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), - .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), - .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), - .component("LineChart"), .component("Table"), .component("TagBlock"), - .component("Form"), .component("Buttons"), .component("IconButton"), - .component("Steps"), .component("InlineHeader"), .component("EntityList"), - .component("EditableTable"), .component("SnippetCardBlock"), - .component("OverviewCardBlock"), .component("ContextCardBlock"), - .component("CompositeCardBlock"), .component("VisualCardBlock"), - .component("ListBlock"), .component("FollowUpBlock"), .component("Tabs"), - .component("Accordion"), - ]))), - ]) - - public static let tabs = ComponentSchema( - "Tabs", description: "Tabbed container", - props: [Prop("items", .array(.component("TabItem")))]) - - public static let tabItem = ComponentSchema( - "TabItem", - description: "value is unique id, trigger is tab label, content is array of components", - props: [ - Prop("value", .string), Prop("trigger", .string), - Prop( - "content", - .array( - .union([ - .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), - .component("Callout"), .component("TextCallout"), .component("CodeBlock"), - .component("Image"), .component("ImageBlock"), .component("ImageGallery"), - .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), - .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), - .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), - .component("LineChart"), .component("Table"), .component("TagBlock"), - .component("Form"), .component("Buttons"), .component("IconButton"), - .component("Steps"), .component("InlineHeader"), .component("EntityList"), - .component("EditableTable"), .component("SnippetCardBlock"), - .component("OverviewCardBlock"), .component("ContextCardBlock"), - .component("CompositeCardBlock"), .component("VisualCardBlock"), - .component("ListBlock"), .component("FollowUpBlock"), .component("Accordion"), - ]))), - ]) - - public static let accordion = ComponentSchema( - "Accordion", description: "Collapsible sections", - props: [Prop("items", .array(.component("AccordionItem")))]) - - public static let accordionItem = ComponentSchema( - "AccordionItem", description: "value is unique id, trigger is section title", - props: [ - Prop("value", .string), Prop("trigger", .string), - Prop( - "content", - .array( - .union([ - .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), - .component("Callout"), .component("TextCallout"), .component("CodeBlock"), - .component("Image"), .component("ImageBlock"), .component("ImageGallery"), - .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), - .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), - .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), - .component("LineChart"), .component("Table"), .component("TagBlock"), - .component("Form"), .component("Buttons"), .component("IconButton"), - .component("Steps"), .component("InlineHeader"), .component("EntityList"), - .component("EditableTable"), .component("SnippetCardBlock"), - .component("OverviewCardBlock"), .component("ContextCardBlock"), - .component("CompositeCardBlock"), .component("VisualCardBlock"), - .component("ListBlock"), .component("FollowUpBlock"), - ]))), - ]) - - public static let carousel = ComponentSchema( - "Carousel", description: "Horizontal scrollable carousel", - props: [ - Prop( - "children", - .array( - .array( - .union([ - .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), - .component("Callout"), .component("TextCallout"), .component("CodeBlock"), - .component("Image"), .component("ImageBlock"), .component("ImageGallery"), - .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), - .component("PieChart"), .component("RadialChart"), - .component("SingleStackedBarChart"), .component("ScatterChart"), - .component("AreaChart"), .component("BarChart"), .component("LineChart"), - .component("Table"), .component("TagBlock"), .component("Form"), - .component("Buttons"), .component("IconButton"), .component("Steps"), - .component("InlineHeader"), .component("EntityList"), .component("EditableTable"), - .component("SnippetCardBlock"), .component("OverviewCardBlock"), - .component("ContextCardBlock"), .component("CompositeCardBlock"), - .component("VisualCardBlock"), .component("ListBlock"), .component("FollowUpBlock"), - ])))), Prop("variant", .enumeration(["card", "sunk"]), .optional), - ]) - - public static let slice = ComponentSchema( - "Slice", description: "One slice with label and numeric value", - props: [Prop("category", .string), Prop("value", .number)]) - - public static let label = ComponentSchema( - "Label", description: "Text label", - props: [Prop("text", .string)]) - - public static let switchGroup = ComponentSchema( - "SwitchGroup", description: "Group of switch toggles", - props: [ - Prop("name", .string), Prop("items", .array(.component("SwitchItem"))), - Prop("variant", .enumeration(["clear", "card", "sunk"]), .optional), - Prop("value", .record(.boolean), .optional, binding: true), - ]) - - public static let switchItem = ComponentSchema( - "SwitchItem", description: "Individual switch toggle", + "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.", props: [ - Prop("label", .string, .optional), Prop("description", .string, .optional), - Prop("name", .string), Prop("defaultChecked", .boolean, .optional), + Prop("items", .array(.component("VisualCardItem"), minItems: 2)), + Prop("layout", .enumeration(["grid", "carousel"]), .defaulted("grid")), + Prop("responsive", .boolean, .defaulted(true)), Prop("action", .actionExpression, .optional), + Prop("gap", .union([.number, .string]), .optional), ]) /// Prompt groups and notes, as in openuiChatLibrary. @@ -948,35 +948,34 @@ public enum ChatComponents { /// Every schema, in library order. public static let all: [ComponentSchema] = [ card, + cardHeader, textContent, markDownRenderer, - cardHeader, callout, textCallout, - codeBlock, image, imageBlock, imageGallery, + codeBlock, separator, + table, + col, + barChart, + lineChart, + areaChart, + radarChart, horizontalBarChart, series, - radarChart, pieChart, radialChart, singleStackedBarChart, + slice, scatterChart, scatterSeries, point, - areaChart, - barChart, - lineChart, - table, - col, - tagBlock, form, - buttons, - button, formControl, + label, input, textArea, select, @@ -987,37 +986,12 @@ public enum ChatComponents { checkBoxItem, radioGroup, radioItem, - chips, - chipItem, - icon, - optionCards, - optionCard, - iconButton, - steps, - stepsItem, - inlineHeader, - entityList, - editableTable, - snippetCardBlock, - snippetCardItem, - iconText, - imageText, - text, - boldText, - overviewCardBlock, - overviewCardItem, - metricIndicatorInline, - contextCardBlock, - contextCardItem, - tag, - compositeCardBlock, - compositeCardItem, - imageTextLarge, + switchGroup, + switchItem, + button, + buttons, listBlock, listItem, - metricIndicatorWithStrikethrough, - visualCardBlock, - visualCardItem, followUpBlock, followUpItem, sectionBlock, @@ -1026,10 +1000,36 @@ public enum ChatComponents { tabItem, accordion, accordionItem, + steps, + stepsItem, carousel, - slice, - label, - switchGroup, - switchItem, + tagBlock, + tag, + entityList, + inlineHeader, + icon, + iconButton, + editableTable, + chipItem, + chips, + optionCard, + optionCards, + text, + boldText, + iconText, + imageText, + imageTextLarge, + metricIndicatorInline, + metricIndicatorWithStrikethrough, + snippetCardItem, + snippetCardBlock, + overviewCardItem, + overviewCardBlock, + contextCardItem, + contextCardBlock, + compositeCardItem, + compositeCardBlock, + visualCardItem, + visualCardBlock, ] } diff --git a/packages/swift-lang/Sources/OpenUILang/CloudConfig.swift b/packages/swift-lang/Sources/OpenUILang/CloudConfig.swift new file mode 100644 index 0000000000..31ef78ec32 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/CloudConfig.swift @@ -0,0 +1,238 @@ +/// OpenUI Cloud's managed system prompt. Port of lang-core's +/// `parser/cloud-config.ts` and `parser/validate-library.ts`. + +/// The config block header. The trailing newline is part of the wire contract. +private let cloudConfigMarker = "]]>openui:config\n" + +/// The version of Cloud's built-in chat library requested when no library is +/// given. Cloud rejects a non-numeric or too-old version. +private let cloudChatLibraryVersion = "0.1.0" + +/// A library OpenUI Cloud can't use, or prompt options it can't apply. +public struct CloudConfigError: Error, CustomStringConvertible { + public var description: String +} + +/// OpenUI Cloud's config block: the Swift version of +/// `generateSystemPrompt({ cloud: true, library, promptOptions, instructions })`. +/// +/// Send it as the system message and Cloud builds the full prompt on its side. +/// Without a library, Cloud uses its built-in chat library. Only `preamble`, +/// `additionalRules` and `examples` are sent; Cloud ignores the other options. +/// +/// - Parameter library: A `LibrarySpec`, as returned by `Library.toSpec()`. +/// - Throws: ``CloudConfigError`` when the library is malformed, or when +/// prompt options are given without a library. +public func generateCloudConfig( + library: OpenUIValue? = nil, promptOptions: PromptOptions? = nil, instructions: String? = nil +) throws -> String { + var config = OpenUIObject() + if let library, library.isTruthy { + let issues = validateChatLibrary(library) + if !issues.isEmpty { + throw CloudConfigError( + description: + "[generateSystemPrompt] Invalid library: \(issues.map(\.message).joined(separator: " "))") + } + var chatLibrary = library.objectValue ?? OpenUIObject() + chatLibrary["components"] = nil + config["chatLibrary"] = .object(chatLibrary) + if let options = promptOptions.flatMap(cloudPromptOptions) { + config["systemPromptOptions"] = .object(options) + } + } else { + if promptOptions.flatMap(cloudPromptOptions) != nil { + throw CloudConfigError( + description: + "[generateSystemPrompt] promptOptions requires a library — the built-in library ignores it." + ) + } + config["libraryVersion"] = .string(cloudChatLibraryVersion) + } + + let block = cloudConfigMarker + JSON.stringify(.object(config)) + if let instructions, !instructions.isEmpty { return "\(block)\n\(instructions)" } + return block +} + +extension Library { + /// This library's OpenUI Cloud config block. See ``generateCloudConfig(library:promptOptions:instructions:)``. + public func cloudConfig(_ options: PromptOptions? = nil, instructions: String? = nil) throws + -> String + { + try generateCloudConfig(library: toSpec(), promptOptions: options, instructions: instructions) + } +} + +/// The options Cloud's prompt assembler reads, in lang-core's key order, or +/// nil when none are set. An empty `preamble` counts as unset, like in JavaScript. +private func cloudPromptOptions(_ options: PromptOptions) -> OpenUIObject? { + var picked = OpenUIObject() + if let examples = options.examples { picked["examples"] = .array(examples.map { .string($0) }) } + if let preamble = options.preamble, !preamble.isEmpty { picked["preamble"] = .string(preamble) } + if let rules = options.additionalRules { + picked["additionalRules"] = .array(rules.map { .string($0) }) + } + return picked.isEmpty ? nil : picked +} + +// MARK: - Library validation + +struct ChatLibraryIssue: Equatable { + enum Code: String { + case invalidShape = "invalid-shape" + case rootNotFound = "root-not-found" + case unresolvedRef = "unresolved-ref" + case unknownGroupComponent = "unknown-group-component" + case invalidRequired = "invalid-required" + } + + var code: Code + var message: String + /// e.g. "$defs/Card/properties/children/items" + var path: String? +} + +/// Structural checks Cloud applies to a library, reporting every issue in one pass. +func validateChatLibrary(_ library: OpenUIValue) -> [ChatLibraryIssue] { + guard let spec = library.objectValue else { + return [ChatLibraryIssue(code: .invalidShape, message: "chatLibrary must be an object.")] + } + var issues: [ChatLibraryIssue] = [] + + let root = spec["root"] ?? .undefined + let rootName = root.stringValue.flatMap { $0.isEmpty ? nil : $0 } + if root != .undefined, rootName == nil { + issues.append( + ChatLibraryIssue( + code: .invalidShape, + message: "chatLibrary.root, when present, must be a non-empty string.", path: "root")) + } + + guard let schema = spec["schema"]?.objectValue else { + issues.append( + ChatLibraryIssue( + code: .invalidShape, + message: "chatLibrary.schema must be an object with a $defs map of component schemas.", + path: "schema")) + return issues + } + guard let defs = schema["$defs"]?.objectValue, !defs.isEmpty else { + issues.append( + ChatLibraryIssue( + code: .invalidShape, + message: "chatLibrary.schema.$defs must be a non-empty object keyed by component name.", + path: "schema/$defs")) + return issues + } + let defNames = Set(defs.keys) + + if let rootName, !defNames.contains(rootName) { + issues.append( + ChatLibraryIssue( + code: .rootNotFound, + message: + "Root component \"\(rootName)\" was not found in schema.$defs. Available components: \(defs.keys.joined(separator: ", ")).", + path: "root")) + } + + for (name, def) in defs.entries { + let defPath = "$defs/\(name)" + guard let component = def.objectValue else { + issues.append( + ChatLibraryIssue( + code: .invalidShape, message: "\(defPath) must be an object component schema.", + path: defPath)) + continue + } + + let properties = component["properties"] ?? .undefined + if properties != .undefined, properties.objectValue == nil { + issues.append( + ChatLibraryIssue( + code: .invalidShape, message: "\(defPath)/properties must be an object.", + path: "\(defPath)/properties")) + } + + let required = component["required"] ?? .undefined + if required != .undefined { + let names = required.arrayValue?.map(\.stringValue) + if let names, names.allSatisfy({ $0 != nil }) { + let propKeys = Set(properties.objectValue?.keys ?? []) + for case let name? in names where !propKeys.contains(name) { + issues.append( + ChatLibraryIssue( + code: .invalidRequired, + message: "\(defPath) lists required property \"\(name)\" that is not in properties.", + path: "\(defPath)/required")) + } + } else { + issues.append( + ChatLibraryIssue( + code: .invalidRequired, + message: "\(defPath)/required must be an array of property names.", + path: "\(defPath)/required")) + } + } + + collectRefIssues(properties, "\(defPath)/properties", defNames, &issues) + } + + for group in spec["componentGroups"]?.arrayValue ?? [] { + guard let groupName = group["name"].stringValue, let components = group["components"].arrayValue + else { + issues.append( + ChatLibraryIssue( + code: .invalidShape, + message: + "Each componentGroups entry must be {name: string, components: string[], notes?: string[]}.", + path: "componentGroups")) + continue + } + for component in components + where !(component.stringValue.map { defNames.contains($0) } ?? false) { + issues.append( + ChatLibraryIssue( + code: .unknownGroupComponent, + message: + "Component group \"\(groupName)\" references unknown component \"\(component.jsString)\".", + path: "componentGroups")) + } + } + + return issues +} + +/// Checks every `$ref` below `node` resolves to a component in `$defs`. +private func collectRefIssues( + _ node: OpenUIValue, _ path: String, _ defNames: Set, _ issues: inout [ChatLibraryIssue] +) { + if let items = node.arrayValue { + for (i, item) in items.enumerated() { + collectRefIssues(item, "\(path)/\(i)", defNames, &issues) + } + return + } + guard let object = node.objectValue else { return } + + if let ref = object["$ref"]?.stringValue, !refResolves(ref, defNames) { + issues.append( + ChatLibraryIssue( + code: .unresolvedRef, + message: + "Unresolvable $ref \"\(ref)\" at \(path) — refs must be \"#/$defs/\" pointing at a component in $defs.", + path: path)) + } + for (key, value) in object.entries where key != "$ref" { + collectRefIssues(value, "\(path)/\(key)", defNames, &issues) + } +} + +/// `/^#\/\$defs\/(.+)$/` plus a `$defs` lookup. `.` doesn't match line terminators. +private func refResolves(_ ref: String, _ defNames: Set) -> Bool { + let prefix = "#/$defs/" + guard ref.hasPrefix(prefix) else { return false } + let name = String(ref.dropFirst(prefix.count)) + let lineTerminators: Set = ["\n", "\r", "\r\n", "\u{2028}", "\u{2029}"] + return !name.isEmpty && !name.contains(where: lineTerminators.contains) && defNames.contains(name) +} diff --git a/packages/swift-lang/Sources/OpenUILang/Library.swift b/packages/swift-lang/Sources/OpenUILang/Library.swift index 4d73af2ca9..404e4dc6e2 100644 --- a/packages/swift-lang/Sources/OpenUILang/Library.swift +++ b/packages/swift-lang/Sources/OpenUILang/Library.swift @@ -166,8 +166,10 @@ func jsonSchema(_ type: PropType) -> OpenUIValue { case .literal(let value): return ["type": .string(value.jsTypeof), "const": value] case .array(let inner, let minItems): - var schema: OpenUIObject = ["type": "array"] + // Zod writes length checks before the type. + var schema = OpenUIObject() if let minItems { schema["minItems"] = .number(Double(minItems)) } + schema["type"] = "array" schema["items"] = jsonSchema(inner) return .object(schema) case .object(let props): return objectSchema(props) @@ -253,12 +255,14 @@ public struct Library: ComponentLibrary { } private static func buildSchema(_ components: [ComponentDefinition]) -> OpenUIValue { - var defs = OpenUIObject() var properties = OpenUIObject() for component in components { - defs[component.name] = component.schema.jsonSchema properties[component.name] = ["$ref": .string("#/$defs/\(component.name)")] } + var defs = OpenUIObject() + for name in definitionOrder(components) { + defs[name] = components.first { $0.name == name }!.schema.jsonSchema + } var root: OpenUIObject = ["$schema": "https://json-schema.org/draft/2020-12/schema"] root["type"] = "object" root["properties"] = .object(properties) @@ -268,6 +272,37 @@ public struct Library: ComponentLibrary { return .object(root) } + /// Zod adds a component to `$defs` the first time its depth-first walk of the + /// library reaches it, so a component referenced by an earlier one comes + /// before its own place in the list. + private static func definitionOrder(_ components: [ComponentDefinition]) -> [String] { + var order: [String] = [] + var seen: Set = [] + + func visit(_ name: String) { + guard !seen.contains(name), let component = components.first(where: { $0.name == name }) + else { return } + seen.insert(name) + order.append(name) + for prop in component.schema.props { walk(prop.type) } + } + + func walk(_ type: PropType) { + switch type { + case .component(let name): visit(name) + case .array(let element, _): walk(element) + case .record(let value): walk(value) + case .named(_, let underlying): walk(underlying) + case .object(let props): for prop in props { walk(prop.type) } + case .union(let options): for option in options { walk(option) } + case .string, .number, .boolean, .any, .enumeration, .literal: break + } + } + + for component in components { visit(component.name) } + return order + } + /// The prompt inputs for this library. public func promptSpec(_ options: PromptOptions = PromptOptions()) -> PromptSpec { PromptSpec( diff --git a/packages/swift-lang/Sources/OpenUILang/Merge.swift b/packages/swift-lang/Sources/OpenUILang/Merge.swift new file mode 100644 index 0000000000..50023d6d1d --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Merge.swift @@ -0,0 +1,136 @@ +/// Edit mode: applies a patch program to an existing one. Port of lang-core's +/// `parser/merge.ts`. + +private struct ParsedStatement { + var id: String + var ast: ASTNode + var raw: String +} + +/// Splits source into top-level statements at newlines outside brackets and +/// strings. Indexes UTF-16 code units, like the JavaScript it mirrors. +private func splitStatementSource(_ input: String) -> [String] { + let units = Array(input.utf16) + var statements: [String] = [] + var depth = 0 + var quote: UInt16? + var escaped = false + var start = 0 + + func appendTrimmed(_ range: Range) { + let statement = jsTrim(String(decoding: units[range], as: UTF16.self)) + if !statement.isEmpty { statements.append(statement) } + } + + for (i, c) in units.enumerated() { + if escaped { + escaped = false + continue + } + if let open = quote { + if c == UInt16(ascii: "\\") { + escaped = true + } else if c == open { + quote = nil + } + continue + } + switch c { + case UInt16(ascii: "\""), UInt16(ascii: "'"): + quote = c + case UInt16(ascii: "("), UInt16(ascii: "["), UInt16(ascii: "{"): + depth += 1 + case UInt16(ascii: ")"), UInt16(ascii: "]"), UInt16(ascii: "}"): + depth = max(0, depth - 1) + case UInt16(ascii: "\n") where depth <= 0: + appendTrimmed(start.. [ParsedStatement] { + let trimmed = jsTrim(input) + if trimmed.isEmpty { return [] } + return splitStatementSource(trimmed).compactMap { raw in + guard let statement = splitStatements(tokenize(raw)).first else { return nil } + return ParsedStatement(id: statement.id, ast: parseExpression(statement.tokens), raw: raw) + } +} + +/// Removes statements unreachable from the root. `$state` declarations are +/// always kept: they're read at runtime, not through references. +private func removeUnreachable( + _ order: inout [String], _ merged: inout [String: String], _ asts: [String: ASTNode], + rootId: String +) { + guard asts[rootId] != nil else { return } + + var reachable: Set = [rootId] + var queue = [rootId] + while let id = queue.popLast() { + asts[id]?.walk { node in + let name: String + switch node { + case .ref(let ref): name = ref + case .runtimeRef(let ref, _): name = ref + default: return + } + if !reachable.contains(name), asts[name] != nil { + reachable.insert(name) + queue.append(name) + } + } + } + for id in order where id.hasPrefix("$") { reachable.insert(id) } + + for id in order where !reachable.contains(id) { merged[id] = nil } + order.removeAll { !reachable.contains($0) } +} + +/// Merges a patch into an existing program. Patch statements replace existing +/// ones with the same name, `name = null` deletes a statement, and statements +/// no longer reachable from `rootId` are dropped. +public func mergeStatements(_ existing: String, _ patch: String, rootId: String = "root") + -> String +{ + let existingStatements = parseStatements(existing) + let patchStatements = parseStatements(stripFences(patch)) + + if existingStatements.isEmpty { + return patchStatements.map(\.raw).joined(separator: "\n") + } + if patchStatements.isEmpty { return existing } + + var merged: [String: String] = [:] + var asts: [String: ASTNode] = [:] + var order: [String] = [] + + // A repeated name stays in `order` twice, as in lang-core; both copies print + // the last definition. + for statement in existingStatements { + order.append(statement.id) + merged[statement.id] = statement.raw + asts[statement.id] = statement.ast + } + + for statement in patchStatements { + if statement.ast == .null { + merged[statement.id] = nil + asts[statement.id] = nil + if let index = order.firstIndex(of: statement.id) { order.remove(at: index) } + continue + } + if merged[statement.id] == nil { order.append(statement.id) } + merged[statement.id] = statement.raw + asts[statement.id] = statement.ast + } + + removeUnreachable(&order, &merged, asts, rootId: rootId) + + return order.compactMap { merged[$0] }.joined(separator: "\n") +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift b/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift index 19c61d2230..aa3f5a42a2 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift +++ b/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift @@ -21,7 +21,18 @@ import Testing } @Test func coversEveryComponentInLibraryOrder() { - #expect(ChatComponents.all.map(\.name) == Self.tsDefs.objectValue?.keys) + #expect(ChatComponents.all.map(\.name) == Self.tsSpec["components"].objectValue?.keys) + } + + @Test func libraryJSONSchemaMatchesByteForByte() { + // Key order included: top-level properties follow library order, $defs + // follow Zod's depth-first discovery order. + let library = Library( + components: ChatComponents.all.map { ComponentDefinition($0, content: ()) }, root: "Card", + componentGroups: ChatComponents.groups) + let schema = JSON.stringify(library.toJSONSchema()) + let expected = JSON.stringify(Fixtures.schemas["chat"]["schema"]) + #expect(schema == expected, "\(firstLineDifference(schema, expected) ?? "")") } @Test func bindingsMatchReactiveProps() { diff --git a/packages/swift-lang/Tests/OpenUILangTests/EditAndCloudTests.swift b/packages/swift-lang/Tests/OpenUILangTests/EditAndCloudTests.swift new file mode 100644 index 0000000000..3f76370862 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/EditAndCloudTests.swift @@ -0,0 +1,70 @@ +import CryptoKit +import Foundation +import Testing + +@testable import OpenUILang + +/// `mergeStatements` must match lang-core's edit-mode merge. +@Suite struct MergeConformanceTests { + @Test(arguments: FixtureCase.all("merge")) + func merge(_ fixture: FixtureCase) { + let value = fixture.value + let merged = mergeStatements( + value["existing"].stringValue!, value["patch"].stringValue!, + rootId: value["rootId"].stringValue ?? "root") + let expected = value["expected"].stringValue! + #expect(merged == expected, "\(fixture.name): \(firstLineDifference(merged, expected) ?? "")") + } +} + +/// `generateCloudConfig` must produce the same config block, or the same +/// error, as `generateSystemPrompt({ cloud: true })`. +@Suite struct CloudConfigConformanceTests { + static let fixtures = Fixtures.load("cloud") + + static var cases: [FixtureCase] { + (fixtures["cases"].arrayValue ?? []).map { + FixtureCase(name: $0["name"].stringValue ?? "?", value: $0) + } + } + + @Test(arguments: cases) + func config(_ fixture: FixtureCase) { + let spec = fixture.value["spec"] + let result = Result { + try generateCloudConfig( + library: spec["library"], promptOptions: Self.promptOptions(spec["promptOptions"]), + instructions: spec["instructions"].stringValue) + } + switch result { + case .success(let config): + #expect(config == fixture.value["expected"].stringValue, "\(fixture.name)") + case .failure(let error): + #expect("\(error)" == fixture.value["error"].stringValue, "\(fixture.name)") + } + } + + @Test func chatLibraryConfigMatchesLangCore() throws { + // lang-core's config for openuiChatLibrary with its prompt options is + // ~80 KB, so the fixture keeps its length and SHA-256. + let chatOptions = FixtureCase.all("prompts").first { $0.name == "chat-options" }!.value["spec"] + let library = Library( + components: ChatComponents.all.map { ComponentDefinition($0, content: ()) }, root: "Card", + componentGroups: ChatComponents.groups) + let config = try library.cloudConfig(Self.promptOptions(chatOptions)) + + let expected = Self.fixtures["chat"] + #expect(Double(config.utf16.count) == expected["length"].numberValue) + let digest = SHA256.hash(data: Data(config.utf8)).map { String(format: "%02x", $0) }.joined() + #expect(digest == expected["sha256"].stringValue) + } + + static func promptOptions(_ value: OpenUIValue) -> PromptOptions? { + guard value.objectValue != nil else { return nil } + let strings = { (key: String) in value[key].arrayValue?.compactMap(\.stringValue) } + return PromptOptions( + preamble: value["preamble"].stringValue, additionalRules: strings("additionalRules"), + examples: strings("examples"), tools: strings("tools")?.map(ToolDescriptor.name), + editMode: value["editMode"].boolValue) + } +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/cloud.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/cloud.json new file mode 100644 index 0000000000..a0394763ea --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/cloud.json @@ -0,0 +1,379 @@ +{ + "cases": [ + { + "name": "built-in", + "spec": {}, + "expected": "]]>openui:config\n{\"libraryVersion\":\"0.1.0\"}" + }, + { + "name": "built-in-instructions", + "spec": { + "instructions": "Answer in French." + }, + "expected": "]]>openui:config\n{\"libraryVersion\":\"0.1.0\"}\nAnswer in French." + }, + { + "name": "built-in-empty-options", + "spec": { + "promptOptions": { + "preamble": "" + } + }, + "expected": "]]>openui:config\n{\"libraryVersion\":\"0.1.0\"}" + }, + { + "name": "built-in-with-options", + "spec": { + "promptOptions": { + "examples": [] + } + }, + "error": "[generateSystemPrompt] promptOptions requires a library — the built-in library ignores it." + }, + { + "name": "library", + "spec": { + "library": { + "root": "Card", + "components": { + "Card": { + "signature": "Card(children: Text[])" + } + }, + "componentGroups": [ + { + "name": "Layout", + "components": [ + "Card", + "Text" + ], + "notes": [ + "- Note" + ] + } + ], + "schema": { + "$defs": { + "Card": { + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/$defs/Text" + } + } + }, + "required": [ + "children" + ] + }, + "Text": { + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ] + } + } + } + } + }, + "expected": "]]>openui:config\n{\"chatLibrary\":{\"root\":\"Card\",\"componentGroups\":[{\"name\":\"Layout\",\"components\":[\"Card\",\"Text\"],\"notes\":[\"- Note\"]}],\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}}}}" + }, + { + "name": "library-options", + "spec": { + "library": { + "root": "Card", + "components": { + "Card": { + "signature": "Card(children: Text[])" + } + }, + "componentGroups": [ + { + "name": "Layout", + "components": [ + "Card", + "Text" + ], + "notes": [ + "- Note" + ] + } + ], + "schema": { + "$defs": { + "Card": { + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/$defs/Text" + } + } + }, + "required": [ + "children" + ] + }, + "Text": { + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ] + } + } + } + }, + "promptOptions": { + "preamble": "Be brief.", + "additionalRules": [ + "One card" + ], + "examples": [ + "a = 1" + ], + "tools": [ + "x" + ], + "editMode": true + }, + "instructions": "Extra." + }, + "expected": "]]>openui:config\n{\"chatLibrary\":{\"root\":\"Card\",\"componentGroups\":[{\"name\":\"Layout\",\"components\":[\"Card\",\"Text\"],\"notes\":[\"- Note\"]}],\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}}},\"systemPromptOptions\":{\"examples\":[\"a = 1\"],\"preamble\":\"Be brief.\",\"additionalRules\":[\"One card\"]}}\nExtra." + }, + { + "name": "library-empty-strings", + "spec": { + "library": { + "root": "Card", + "components": { + "Card": { + "signature": "Card(children: Text[])" + } + }, + "componentGroups": [ + { + "name": "Layout", + "components": [ + "Card", + "Text" + ], + "notes": [ + "- Note" + ] + } + ], + "schema": { + "$defs": { + "Card": { + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/$defs/Text" + } + } + }, + "required": [ + "children" + ] + }, + "Text": { + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ] + } + } + } + }, + "promptOptions": { + "preamble": "" + }, + "instructions": "" + }, + "expected": "]]>openui:config\n{\"chatLibrary\":{\"root\":\"Card\",\"componentGroups\":[{\"name\":\"Layout\",\"components\":[\"Card\",\"Text\"],\"notes\":[\"- Note\"]}],\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}}}}" + }, + { + "name": "library-without-root", + "spec": { + "library": { + "components": { + "Card": { + "signature": "Card(children: Text[])" + } + }, + "schema": { + "$defs": { + "Card": { + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/$defs/Text" + } + } + }, + "required": [ + "children" + ] + }, + "Text": { + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ] + } + } + } + } + }, + "expected": "]]>openui:config\n{\"chatLibrary\":{\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}}}}" + }, + { + "name": "library-with-id", + "spec": { + "library": { + "root": "Card", + "components": { + "Card": { + "signature": "Card(children: Text[])" + } + }, + "componentGroups": [ + { + "name": "Layout", + "components": [ + "Card", + "Text" + ], + "notes": [ + "- Note" + ] + } + ], + "schema": { + "$defs": { + "Card": { + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/$defs/Text" + } + } + }, + "required": [ + "children" + ] + }, + "Text": { + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ] + } + } + }, + "id": "lib-1" + } + }, + "expected": "]]>openui:config\n{\"chatLibrary\":{\"root\":\"Card\",\"componentGroups\":[{\"name\":\"Layout\",\"components\":[\"Card\",\"Text\"],\"notes\":[\"- Note\"]}],\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}},\"id\":\"lib-1\"}}" + }, + { + "name": "broken-library", + "spec": { + "library": { + "root": "Missing", + "components": {}, + "componentGroups": [ + { + "name": "G", + "components": [ + "Card", + "Nope" + ] + }, + { + "name": 1 + } + ], + "schema": { + "$defs": { + "Card": { + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/$defs/Gone" + } + }, + "x": { + "$ref": "bad" + } + }, + "required": [ + "children", + "absent", + 3 + ] + }, + "Text": { + "properties": [] + }, + "Bad": "nope" + } + } + } + }, + "error": "[generateSystemPrompt] Invalid library: Root component \"Missing\" was not found in schema.$defs. Available components: Card, Text, Bad. $defs/Card/required must be an array of property names. Unresolvable $ref \"#/$defs/Gone\" at $defs/Card/properties/children/items — refs must be \"#/$defs/\" pointing at a component in $defs. Unresolvable $ref \"bad\" at $defs/Card/properties/x — refs must be \"#/$defs/\" pointing at a component in $defs. $defs/Text/properties must be an object. $defs/Bad must be an object component schema. Component group \"G\" references unknown component \"Nope\". Each componentGroups entry must be {name: string, components: string[], notes?: string[]}." + }, + { + "name": "no-defs", + "spec": { + "library": { + "components": {}, + "schema": { + "$defs": {} + } + } + }, + "error": "[generateSystemPrompt] Invalid library: chatLibrary.schema.$defs must be a non-empty object keyed by component name." + }, + { + "name": "no-schema", + "spec": { + "library": { + "root": "", + "components": {} + } + }, + "error": "[generateSystemPrompt] Invalid library: chatLibrary.root, when present, must be a non-empty string. chatLibrary.schema must be an object with a $defs map of component schemas." + } + ], + "chat": { + "length": 83747, + "sha256": "57e211d92850453a1be46c1e7653d40ec0714b309cef203f4eba589dde7e4f3e" + } +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/merge.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/merge.json new file mode 100644 index 0000000000..1cd7ad7630 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/merge.json @@ -0,0 +1,117 @@ +[ + { + "name": "empty-existing", + "existing": "", + "patch": "root = Card([a])\na = TextContent(\"x\")", + "expected": "root = Card([a])\na = TextContent(\"x\")" + }, + { + "name": "empty-patch", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", + "patch": " \n", + "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" + }, + { + "name": "replace", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", + "patch": "title = TextContent(\"Q4\", \"large\")", + "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q4\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" + }, + { + "name": "add-referenced", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", + "patch": "root = Card([title, body, note])\nnote = Callout(\"info\", \"Hi\")", + "expected": "root = Card([title, body, note])\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"\nnote = Callout(\"info\", \"Hi\")" + }, + { + "name": "add-unreferenced", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", + "patch": "orphan = TextContent(\"never shown\")", + "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" + }, + { + "name": "delete", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", + "patch": "body = null\nroot = Card([title])", + "expected": "root = Card([title])\ntitle = TextContent(\"Q3\", \"large\")\n$filter = \"all\"" + }, + { + "name": "gc-after-replace", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", + "patch": "body = TextContent(\"no table\")", + "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = TextContent(\"no table\")\n$filter = \"all\"" + }, + { + "name": "keeps-unused-state", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", + "patch": "root = Card([title])\n$extra = 1", + "expected": "root = Card([title])\ntitle = TextContent(\"Q3\", \"large\")\n$filter = \"all\"\n$extra = 1" + }, + { + "name": "root-deleted", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", + "patch": "root = null", + "expected": "title = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" + }, + { + "name": "fenced-patch", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", + "patch": "```openui\ntitle = TextContent(\"Fenced\")\n```", + "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Fenced\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" + }, + { + "name": "multiline-and-strings", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", + "patch": "body = Table([\n colA,\n colB\n])\ntitle = TextContent(\"a ) ] } \\\" ' \\n\", \"large\")", + "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"a ) ] } \\\" ' \\n\", \"large\")\nbody = Table([\n colA,\n colB\n])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" + }, + { + "name": "single-quotes", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", + "patch": "title = TextContent('it\\'s (fine')", + "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent('it\\'s (fine')\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" + }, + { + "name": "crlf", + "existing": "root = Card([title, body, $filter], \"Report\")\r\ntitle = TextContent(\"Q3\", \"large\")\r\nbody = Table([colA, colB])\r\ncolA = Col(\"Region\", [\"EU\", \"US\"])\r\ncolB = Col(\"Revenue\", [1, 2])\r\n$filter = \"all\"", + "patch": "title = TextContent(\"CRLF\")\r\n", + "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"CRLF\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" + }, + { + "name": "duplicate-existing", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"\ntitle = TextContent(\"dup\")", + "patch": "colA = Col(\"Area\", [])", + "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"dup\")\nbody = Table([colA, colB])\ncolA = Col(\"Area\", [])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"\ntitle = TextContent(\"dup\")" + }, + { + "name": "delete-then-add", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", + "patch": "title = null\ntitle = TextContent(\"back\")", + "expected": "root = Card([title, body, $filter], \"Report\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"\ntitle = TextContent(\"back\")" + }, + { + "name": "query-refs", + "existing": "root = Card([t])\nt = Table([c])\nc = Col(\"n\", q.rows)\nq = Query(\"list\", {}, {rows: []})", + "patch": "c = Col(\"name\", q.rows)", + "expected": "root = Card([t])\nt = Table([c])\nc = Col(\"name\", q.rows)\nq = Query(\"list\", {}, {rows: []})" + }, + { + "name": "custom-root", + "existing": "main = Card([a])\na = TextContent(\"x\")\nb = TextContent(\"y\")", + "patch": "a = TextContent(\"z\")", + "rootId": "main", + "expected": "main = Card([a])\na = TextContent(\"z\")" + }, + { + "name": "unclosed-patch", + "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", + "patch": "title = TextContent(\"cut", + "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"cut\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" + }, + { + "name": "chat-example", + "existing": "Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }", + "patch": "header = CardHeader(\"Edited\", \"by a patch\")", + "expected": "root = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Edited\", \"by a patch\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }" + } +] diff --git a/packages/swift-lang/Tests/OpenUILangTests/JSSemanticsTests.swift b/packages/swift-lang/Tests/OpenUILangTests/JSSemanticsTests.swift index 1a72658fcd..d4ba02da08 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/JSSemanticsTests.swift +++ b/packages/swift-lang/Tests/OpenUILangTests/JSSemanticsTests.swift @@ -8,7 +8,7 @@ import Testing @Test(arguments: [ (0.0, "0"), (-0.0, "0"), (1, "1"), (-1, "-1"), (0.1 + 0.2, "0.30000000000000004"), (100, "100"), (1e21, "1e+21"), (1e-7, "1e-7"), (1.5e-7, "1.5e-7"), (123e-20, "1.23e-18"), - (1e20, "100000000000000000000"), (123_456_789_012_345_680_000, "123456789012345680000"), + (1e20, "100000000000000000000"), (1.2345678901234568e20, "123456789012345680000"), (0.000001, "0.000001"), (5e-324, "5e-324"), (1.797_693_134_862_315_7e308, "1.7976931348623157e+308"), (.nan, "NaN"), (.infinity, "Infinity"), (-.infinity, "-Infinity"), (2.5, "2.5"), (-2.5e-3, "-0.0025"), From 317a930edfa5755d8dd7429d34ac9027d43b9d70 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 00:53:50 +0530 Subject: [PATCH 07/52] feat(swift-lang): report errors and parse results like react-lang's Renderer OpenUIRuntime gains onError and onParseResult, ported from react-lang's useOpenUIErrors: parser errors carry enrichErrors' hints, a response with no root reports parse-failed, failed Query/Mutation calls are included, and errors are reported once streaming ends and cleared when the next response starts. OpenUIRenderer passes both through and takes a custom queryLoader view, defaulting to a small spinner like the React renderer. Hints are checked against lang-core's enrichErrors, and the parser fixtures now include a response in OpenUI Cloud's content/end marker format. --- .../swift-lang/Scripts/generate-fixtures.mjs | 28 ++++- .../swift-lang/Sources/OpenUILang/JSON.swift | 15 +++ .../Sources/OpenUILang/Library.swift | 2 + .../Sources/OpenUILang/Runtime.swift | 103 +++++++++++++-- .../swift-lang/Sources/OpenUILang/Types.swift | 2 +- .../Sources/OpenUISwiftUI/OpenUIContext.swift | 4 + .../OpenUISwiftUI/OpenUIRenderer.swift | 50 +++++++- .../OpenUILangTests/ErrorReportingTests.swift | 87 +++++++++++++ .../OpenUILangTests/Fixtures/errors.json | 119 ++++++++++++++++++ .../OpenUILangTests/Fixtures/parser.json | 49 ++++++++ .../OpenUILangTests/Fixtures/streaming.json | 2 +- .../OpenUISwiftUITests/RendererTests.swift | 21 ++++ 12 files changed, 468 insertions(+), 14 deletions(-) create mode 100644 packages/swift-lang/Tests/OpenUILangTests/ErrorReportingTests.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/Fixtures/errors.json diff --git a/packages/swift-lang/Scripts/generate-fixtures.mjs b/packages/swift-lang/Scripts/generate-fixtures.mjs index ab41336640..8b11e795a0 100644 --- a/packages/swift-lang/Scripts/generate-fixtures.mjs +++ b/packages/swift-lang/Scripts/generate-fixtures.mjs @@ -232,6 +232,13 @@ const edgeCases = [ ), t("truncated-mid-call", 'root = Card([a, b])\na = Text("one")\nb = Button("tw'), t("truncated-mid-object", 'root = Card([Chart(["a"], [1], {unit: "k'), + // OpenUI Cloud's wire format: a content marker, a fenced program, an end marker. + { + name: "cloud-envelope", + schema: "chat", + input: + ']]>openui:content?thesys=true\n```openui-lang\nroot = Card([h, t])\nh = CardHeader("Q3", "Revenue")\nt = TextContent("Up 12%")\n```\n]]>openui:end', + }, ]; // ── Fixture generation ──────────────────────────────────────────────────── @@ -511,6 +518,24 @@ const mergeCases = [ }, ].map((c) => ({ ...c, expected: core.mergeStatements(c.existing, c.patch, c.rootId) })); +// ── Error hints ─────────────────────────────────────────────────────────── + +// What react-lang's onError reports for parser errors: lang-core's enrichErrors. +const chatNames = Object.keys(ui.openuiChatLibrary.components); +const errorCases = [ + ["unknown-component", 'root = Card([Mystery("a"), TextContent("b")])'], + ["missing-required", "root = Card([TextContent()])"], + ["null-required", "root = Card([TextContent(null)])"], + ["inline-reserved", 'root = Card([TextContent(Query("get", {}))])'], + ["excess-args", 'root = Card([CardHeader("a", "b", "c", "d")])'], + ["type-mismatch", "root = Card([TextContent(42)])"], + ["several", "root = Card([a, b])\na = Foo()\nb = Button()"], +].map(([name, input]) => ({ + name, + input, + expected: core.enrichErrors(parseWith("chat", input).meta.errors, chatSchema, chatNames), +})); + // ── Cloud config ────────────────────────────────────────────────────────── const cloudLibrary = { @@ -609,6 +634,7 @@ write("stream-set.json", setCases); write("evaluation.json", evalFixtures); write("prompts.json", promptCases); write("merge.json", mergeCases); +write("errors.json", errorCases); write("cloud.json", { cases: cloudCases, chat: chatCloud }); // The chat examples, for the SwiftUI renderer's end-to-end render tests. @@ -624,5 +650,5 @@ writeFileSync( write("chat-spec.json", chatComponentSpecs); console.log( - `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set, ${evalFixtures.length} evaluation, ${promptCases.length} prompt, ${mergeCases.length} merge, ${cloudCases.length} cloud fixtures`, + `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set, ${evalFixtures.length} evaluation, ${promptCases.length} prompt, ${mergeCases.length} merge, ${errorCases.length} error, ${cloudCases.length} cloud fixtures`, ); diff --git a/packages/swift-lang/Sources/OpenUILang/JSON.swift b/packages/swift-lang/Sources/OpenUILang/JSON.swift index df71432f34..c8f58b4cf6 100644 --- a/packages/swift-lang/Sources/OpenUILang/JSON.swift +++ b/packages/swift-lang/Sources/OpenUILang/JSON.swift @@ -386,6 +386,21 @@ extension ValidationError { } } +extension OpenUIError { + public var jsonRepresentation: OpenUIValue { + var object = OpenUIObject() + object["source"] = .string(source.rawValue) + object["code"] = .string(code) + object["message"] = .string(message) + if let statementId { object["statementId"] = .string(statementId) } + if let component { object["component"] = .string(component) } + if let path { object["path"] = .string(path) } + if let toolName { object["toolName"] = .string(toolName) } + if let hint { object["hint"] = .string(hint) } + return .object(object) + } +} + extension ParseResult { public var jsonRepresentation: OpenUIValue { var meta = OpenUIObject() diff --git a/packages/swift-lang/Sources/OpenUILang/Library.swift b/packages/swift-lang/Sources/OpenUILang/Library.swift index 404e4dc6e2..5b540c19cf 100644 --- a/packages/swift-lang/Sources/OpenUILang/Library.swift +++ b/packages/swift-lang/Sources/OpenUILang/Library.swift @@ -241,6 +241,8 @@ public struct Library: ComponentLibrary { public var rootName: String? { root } + public var componentNames: [String] { components.map(\.name) } + public func component(named name: String) -> ComponentDefinition? { byName[name].map { components[$0] } } diff --git a/packages/swift-lang/Sources/OpenUILang/Runtime.swift b/packages/swift-lang/Sources/OpenUILang/Runtime.swift index 47c7e8576b..358a800775 100644 --- a/packages/swift-lang/Sources/OpenUILang/Runtime.swift +++ b/packages/swift-lang/Sources/OpenUILang/Runtime.swift @@ -6,6 +6,12 @@ public protocol ComponentLibrary { var rootName: String? { get } /// Whether a prop binds two-way to `$state` (lang-core's `reactive()`). func isReactiveProp(_ component: String, _ prop: String) -> Bool + /// Component names in library order, listed in error hints. + var componentNames: [String] { get } +} + +extension ComponentLibrary { + public var componentNames: [String] { paramMap.componentNames } } /// The framework-independent runtime behind a renderer: streaming parse, @@ -21,6 +27,14 @@ public final class OpenUIRuntime { public var onAction: ((ActionEvent) -> Void)? /// Called when state changes after initialization. public var onStateUpdate: ((OpenUIObject) -> Void)? + /// Called whenever the parse result changes. + public var onParseResult: ((ParseResult?) -> Void)? + /// Called with structured errors an LLM can fix by changing the response: + /// parser validation errors with hints, a response without a root, and + /// failed Query/Mutation calls. Reported once streaming finishes, and with + /// `[]` when they clear or the next response starts streaming, so a + /// correction loop gets a clean signal. Matches react-lang's `onError`. + public var onError: (([OpenUIError]) -> Void)? public private(set) var parseResult: ParseResult? public private(set) var isStreaming = false @@ -29,7 +43,11 @@ public final class OpenUIRuntime { private let initialState: OpenUIObject? private var storeInitKey: String? private var initializingStore = false - private var unsubscribe: (() -> Void)? + private var unsubscribers: [() -> Void] = [] + private var response: String? + private var hasParsed = false + /// The errors last passed to `onError`; nil when nothing is reported. + private var reportedErrors: [OpenUIError]? public init( library: some ComponentLibrary, initialState: OpenUIObject? = nil, @@ -39,16 +57,18 @@ public final class OpenUIRuntime { self.initialState = initialState self.streamParser = StreamParser(library.paramMap, rootName: library.rootName) self.queries = QueryManager(toolProvider: toolProvider) - unsubscribe = store.subscribe { [weak self] in - guard let self, !self.initializingStore else { return } - self.onStateUpdate?(self.store.snapshot) - } + unsubscribers.append( + store.subscribe { [weak self] in + guard let self, !self.initializingStore else { return } + self.onStateUpdate?(self.store.snapshot) + }) + unsubscribers.append(queries.subscribe { [weak self] in self?.reportErrors() }) } /// Stops query refreshes and drops listeners. public func dispose() { - unsubscribe?() - unsubscribe = nil + for unsubscribe in unsubscribers { unsubscribe() } + unsubscribers.removeAll() queries.dispose() } @@ -57,11 +77,19 @@ public final class OpenUIRuntime { /// Feeds the latest full response text. Appended text parses incrementally. public func update(response: String?, isStreaming: Bool) { self.isStreaming = isStreaming + defer { reportErrors() } + let changed = !hasParsed || response != self.response + hasParsed = true + self.response = response guard let response, !response.isEmpty else { parseResult = nil + if changed { onParseResult?(nil) } return } - parseResult = streamParser.set(response) + if changed { + parseResult = streamParser.set(response) + onParseResult?(parseResult) + } initializeStoreIfNeeded() if !isStreaming { syncQueries() } } @@ -89,6 +117,65 @@ public final class OpenUIRuntime { store.initialize(defaults: declarations, persisted: bindingDefaults) } + // MARK: Errors + + /// The errors `onError` reports for the current response and query state. + /// Ports react-lang's `useOpenUIErrors`. Prop evaluation and SwiftUI views + /// can't throw, so there are no `runtime-error` or `render-error` entries. + public var errors: [OpenUIError] { + var errors: [OpenUIError] = [] + if let response, !response.isEmpty, parseResult?.root == nil { + errors.append( + OpenUIError( + source: .parser, code: "parse-failed", + message: "Code parsed but produced no renderable root component", + hint: + "The entire response must be valid openui-lang code starting with root = \(library.rootName ?? "Root")(...)" + )) + } + errors += (parseResult?.meta.errors ?? []).map(withHint) + errors += queries.snapshot.errors + return errors + } + + private func reportErrors() { + guard let onError else { return } + if isStreaming { + if reportedErrors != nil { + reportedErrors = nil + onError([]) + } + return + } + let errors = errors + guard errors != reportedErrors else { return } + reportedErrors = errors + onError(errors) + } + + /// A validation error as an `OpenUIError`, with the fix hint lang-core's + /// `enrichErrors` adds. + private func withHint(_ error: ValidationError) -> OpenUIError { + var result = OpenUIError( + source: .parser, code: error.code.rawValue, message: error.message, + statementId: error.statementId, component: error.component, + path: error.path.isEmpty ? nil : error.path) + switch error.code { + case .unknownComponent where !library.componentNames.isEmpty: + result.hint = "Available components: \(library.componentNames.joined(separator: ", "))" + case .missingRequired, .nullRequired: + result.hint = library.paramMap[error.component].map { params in + let names = params.map { $0.required ? "\($0.name)*" : $0.name } + return "Signature: \(error.component)(\(names.joined(separator: ", "))) — * marks required" + } + case .inlineReserved: + result.hint = "Declare as a top-level statement: myVar = \(error.component)(...)" + default: + break + } + return result + } + // MARK: Evaluation /// Reads state for expressions (form fields store `{ value, componentType }`) diff --git a/packages/swift-lang/Sources/OpenUILang/Types.swift b/packages/swift-lang/Sources/OpenUILang/Types.swift index 985502389a..f8b121b692 100644 --- a/packages/swift-lang/Sources/OpenUILang/Types.swift +++ b/packages/swift-lang/Sources/OpenUILang/Types.swift @@ -206,7 +206,7 @@ public struct ParamDef: Sendable, Equatable { public var schema: OpenUIValue? } -/// Positional parameter lists keyed by component name, in library order. +/// Positional parameter lists keyed by component name, in schema `$defs` order. public struct ParamMap: Sendable, Equatable { public var componentNames: [String] = [] private var params: [String: [ParamDef]] = [:] diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift index 4486968184..13f9abd27b 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift @@ -34,6 +34,8 @@ public final class OpenUIContext { @ObservationIgnored var onAction: ((ActionEvent) -> Void)? @ObservationIgnored var onStateUpdate: ((OpenUIObject) -> Void)? + @ObservationIgnored var onParseResult: ((ParseResult?) -> Void)? + @ObservationIgnored var onError: (([OpenUIError]) -> Void)? @ObservationIgnored private var unsubscribers: [() -> Void] = [] public init( @@ -45,6 +47,8 @@ public final class OpenUIContext { library: library, initialState: initialState, toolProvider: toolProvider) runtime.onAction = { [weak self] event in self?.onAction?(event) } runtime.onStateUpdate = { [weak self] state in self?.onStateUpdate?(state) } + runtime.onParseResult = { [weak self] result in self?.onParseResult?(result) } + runtime.onError = { [weak self] errors in self?.onError?(errors) } unsubscribers.append(runtime.store.subscribe { [weak self] in self?.revision += 1 }) unsubscribers.append(runtime.queries.subscribe { [weak self] in self?.revision += 1 }) } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift index 21823fa3c9..977705ef51 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift @@ -9,11 +9,14 @@ import SwiftUI /// event in send(event.humanFriendlyMessage) /// } /// ``` -public struct OpenUIRenderer: View { +public struct OpenUIRenderer: View { let response: String? let isStreaming: Bool + let queryLoader: QueryLoader let onAction: ((ActionEvent) -> Void)? let onStateUpdate: ((OpenUIObject) -> Void)? + let onParseResult: ((ParseResult?) -> Void)? + let onError: (([OpenUIError]) -> Void)? @State private var context: OpenUIContext @@ -23,19 +26,29 @@ public struct OpenUIRenderer: View { /// - library: The components the response may use. Changing it requires a new view identity. /// - initialState: Restored `$state` and form values, e.g. from a saved conversation. /// - toolProvider: Handles `Query` and `Mutation` tool calls. - /// - onStateUpdate: Called when `$state` or form values change. + /// - queryLoader: Shown in the top trailing corner while queries load. /// - onAction: Called for actions the host handles (continue the conversation, open a URL). /// A trailing closure binds here. + /// - onStateUpdate: Called when `$state` or form values change. + /// - onParseResult: Called whenever the parse result changes. + /// - onError: Called with errors an LLM can fix once the response finishes, and with `[]` + /// when they clear. See `OpenUIRuntime.onError`. public init( response: String?, isStreaming: Bool = false, library: SwiftUILibrary, initialState: OpenUIObject? = nil, toolProvider: (any ToolProvider)? = nil, + queryLoader: QueryLoader, onAction: ((ActionEvent) -> Void)? = nil, - onStateUpdate: ((OpenUIObject) -> Void)? = nil + onStateUpdate: ((OpenUIObject) -> Void)? = nil, + onParseResult: ((ParseResult?) -> Void)? = nil, + onError: (([OpenUIError]) -> Void)? = nil ) { self.response = response self.isStreaming = isStreaming + self.queryLoader = queryLoader self.onAction = onAction self.onStateUpdate = onStateUpdate + self.onParseResult = onParseResult + self.onError = onError _context = State( initialValue: OpenUIContext( library: library, initialState: initialState, toolProvider: toolProvider)) @@ -48,6 +61,9 @@ public struct OpenUIRenderer: View { OpenUIElementView(element: root) .opacity(context.isQueryLoading ? 0.7 : 1) .animation(.easeInOut(duration: 0.2), value: context.isQueryLoading) + .overlay(alignment: .topTrailing) { + if context.isQueryLoading { queryLoader.padding(8) } + } } } .environment(context) @@ -64,6 +80,34 @@ public struct OpenUIRenderer: View { private func syncHandlers() -> Bool { context.onAction = onAction context.onStateUpdate = onStateUpdate + context.onParseResult = onParseResult + context.onError = onError return true } } + +extension OpenUIRenderer where QueryLoader == DefaultQueryLoader { + /// A renderer with the default query loading indicator. + public init( + response: String?, isStreaming: Bool = false, library: SwiftUILibrary, + initialState: OpenUIObject? = nil, toolProvider: (any ToolProvider)? = nil, + onAction: ((ActionEvent) -> Void)? = nil, + onStateUpdate: ((OpenUIObject) -> Void)? = nil, + onParseResult: ((ParseResult?) -> Void)? = nil, + onError: (([OpenUIError]) -> Void)? = nil + ) { + self.init( + response: response, isStreaming: isStreaming, library: library, initialState: initialState, + toolProvider: toolProvider, queryLoader: DefaultQueryLoader(), onAction: onAction, + onStateUpdate: onStateUpdate, onParseResult: onParseResult, onError: onError) + } +} + +/// The small spinner shown while queries load. +public struct DefaultQueryLoader: View { + public init() {} + + public var body: some View { + ProgressView().controlSize(.small) + } +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/ErrorReportingTests.swift b/packages/swift-lang/Tests/OpenUILangTests/ErrorReportingTests.swift new file mode 100644 index 0000000000..710e957cf9 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/ErrorReportingTests.swift @@ -0,0 +1,87 @@ +import Testing + +@testable import OpenUILang + +/// `OpenUIRuntime.onError` must report what react-lang's `onError` does. +@MainActor +@Suite struct ErrorReportingTests { + static let library = Library( + components: ChatComponents.all.map { ComponentDefinition($0, content: ()) }, root: "Card", + componentGroups: ChatComponents.groups) + + /// Collects every `onError` call. + final class Reports { + var calls: [[OpenUIError]] = [] + } + + func makeRuntime(toolProvider: (any ToolProvider)? = nil) -> (OpenUIRuntime, Reports) { + let runtime = OpenUIRuntime(library: Self.library, toolProvider: toolProvider) + let reports = Reports() + runtime.onError = { reports.calls.append($0) } + return (runtime, reports) + } + + @Test(arguments: FixtureCase.all("errors")) + func parserErrorHintsMatchLangCore(_ fixture: FixtureCase) { + let (runtime, reports) = makeRuntime() + runtime.update(response: fixture.value["input"].stringValue!, isStreaming: false) + let reported = OpenUIValue.array((reports.calls.last ?? []).map(\.jsonRepresentation)) + let diff = firstDifference(normalized(reported), normalized(fixture.value["expected"])) + #expect(diff == nil, "\(fixture.name): \(diff ?? "")") + } + + @Test func reportsOnlyAfterStreamingAndOnlyOnChange() { + let (runtime, reports) = makeRuntime() + runtime.update(response: "root = Card([Mystery(", isStreaming: true) + #expect(reports.calls.isEmpty) + + runtime.update(response: "root = Card([Mystery()])", isStreaming: false) + #expect(reports.calls.map { $0.map(\.code) } == [["unknown-component"]]) + runtime.update(response: "root = Card([Mystery()])", isStreaming: false) + #expect(reports.calls.count == 1) + + // The next response clears the errors as soon as it starts streaming. + runtime.update(response: "root = Card([", isStreaming: true) + runtime.update(response: "root = Card([TextContent(", isStreaming: true) + #expect(reports.calls.count == 2 && reports.calls[1].isEmpty) + + runtime.update(response: "root = Card([TextContent(\"ok\")])", isStreaming: false) + #expect(reports.calls.count == 3 && reports.calls[2].isEmpty) + } + + @Test func reportsAResponseWithoutARoot() { + let (runtime, reports) = makeRuntime() + runtime.update(response: "Here is a summary in plain text.", isStreaming: false) + let error = reports.calls.last?.first + #expect(error?.code == "parse-failed") + #expect(error?.message == "Code parsed but produced no renderable root component") + #expect( + error?.hint + == "The entire response must be valid openui-lang code starting with root = Card(...)") + } + + @Test func reportsFailedQueriesWhenTheyFinish() async { + let (runtime, reports) = makeRuntime( + toolProvider: FunctionToolProvider(["other": { _ in .null }])) + runtime.update( + response: "root = Card([TextContent(\"x\")])\nq = Query(\"missing_tool\", {}, {})", + isStreaming: false) + for _ in 0..<20 { await Task.yield() } + let last = reports.calls.last ?? [] + #expect(last.map(\.code) == ["tool-not-found"]) + #expect(last.first?.toolName == "missing_tool") + } + + @Test func reportsParseResultChanges() { + let runtime = OpenUIRuntime(library: Self.library) + var results: [ParseResult?] = [] + runtime.onParseResult = { results.append($0) } + runtime.update(response: nil, isStreaming: false) + runtime.update(response: "root = Card([", isStreaming: true) + runtime.update(response: "root = Card([", isStreaming: false) + runtime.update(response: "root = Card([TextContent(\"a\")])", isStreaming: false) + #expect(results.count == 3) + #expect(results[0] == nil) + #expect(results[2]?.root?.typeName == "Card") + } +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/errors.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/errors.json new file mode 100644 index 0000000000..c9bbb1ab45 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/errors.json @@ -0,0 +1,119 @@ +[ + { + "name": "unknown-component", + "input": "root = Card([Mystery(\"a\"), TextContent(\"b\")])", + "expected": [ + { + "source": "parser", + "code": "unknown-component", + "message": "Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, TextContent, MarkDownRenderer, CardHeader, Callout, TextCallout, CodeBlock, Image, ImageBlock, ImageGallery, Separator, HorizontalBarChart, Series, RadarChart, PieChart, RadialChart, SingleStackedBarChart, ScatterChart, ScatterSeries, Point, AreaChart, BarChart, LineChart, Table, Col, TagBlock, Form, Buttons, Button, FormControl, Input, TextArea, Select, SelectItem, DatePicker, Slider, CheckBoxGroup, CheckBoxItem, RadioGroup, RadioItem, Chips, ChipItem, Icon, OptionCards, OptionCard, IconButton, Steps, StepsItem, InlineHeader, EntityList, EditableTable, SnippetCardBlock, SnippetCardItem, IconText, ImageText, Text, BoldText, OverviewCardBlock, OverviewCardItem, MetricIndicatorInline, ContextCardBlock, ContextCardItem, Tag, CompositeCardBlock, CompositeCardItem, ImageTextLarge, ListBlock, ListItem, MetricIndicatorWithStrikethrough, VisualCardBlock, VisualCardItem, FollowUpBlock, FollowUpItem, SectionBlock, SectionItem, Tabs, TabItem, Accordion, AccordionItem, Carousel, Slice, Label, SwitchGroup, SwitchItem", + "component": "Mystery", + "statementId": "root", + "hint": "Available components: Card, CardHeader, TextContent, MarkDownRenderer, Callout, TextCallout, Image, ImageBlock, ImageGallery, CodeBlock, Separator, Table, Col, BarChart, LineChart, AreaChart, RadarChart, HorizontalBarChart, Series, PieChart, RadialChart, SingleStackedBarChart, Slice, ScatterChart, ScatterSeries, Point, Form, FormControl, Label, Input, TextArea, Select, SelectItem, DatePicker, Slider, CheckBoxGroup, CheckBoxItem, RadioGroup, RadioItem, SwitchGroup, SwitchItem, Button, Buttons, ListBlock, ListItem, FollowUpBlock, FollowUpItem, SectionBlock, SectionItem, Tabs, TabItem, Accordion, AccordionItem, Steps, StepsItem, Carousel, TagBlock, Tag, EntityList, InlineHeader, Icon, IconButton, EditableTable, ChipItem, Chips, OptionCard, OptionCards, Text, BoldText, IconText, ImageText, ImageTextLarge, MetricIndicatorInline, MetricIndicatorWithStrikethrough, SnippetCardItem, SnippetCardBlock, OverviewCardItem, OverviewCardBlock, ContextCardItem, ContextCardBlock, CompositeCardItem, CompositeCardBlock, VisualCardItem, VisualCardBlock" + } + ] + }, + { + "name": "missing-required", + "input": "root = Card([TextContent()])", + "expected": [ + { + "source": "parser", + "code": "missing-required", + "message": "missing required field \"/text\" — signature: TextContent(text*: string, size: \"small\"|\"default\"|\"large\"|\"small-heavy\"|\"large-heavy\")", + "component": "TextContent", + "path": "/text", + "statementId": "root", + "hint": "Signature: TextContent(text*, size) — * marks required" + } + ] + }, + { + "name": "null-required", + "input": "root = Card([TextContent(null)])", + "expected": [ + { + "source": "parser", + "code": "null-required", + "message": "required field \"/text\" cannot be null — signature: TextContent(text*: string, size: \"small\"|\"default\"|\"large\"|\"small-heavy\"|\"large-heavy\")", + "component": "TextContent", + "path": "/text", + "statementId": "root", + "hint": "Signature: TextContent(text*, size) — * marks required" + } + ] + }, + { + "name": "inline-reserved", + "input": "root = Card([TextContent(Query(\"get\", {}))])", + "expected": [ + { + "source": "parser", + "code": "inline-reserved", + "message": "Query() must be declared as a top-level statement, not used inline as a value", + "component": "Query", + "statementId": "root", + "hint": "Declare as a top-level statement: myVar = Query(...)" + }, + { + "source": "parser", + "code": "null-required", + "message": "required field \"/text\" cannot be null — signature: TextContent(text*: string, size: \"small\"|\"default\"|\"large\"|\"small-heavy\"|\"large-heavy\")", + "component": "TextContent", + "path": "/text", + "statementId": "root", + "hint": "Signature: TextContent(text*, size) — * marks required" + } + ] + }, + { + "name": "excess-args", + "input": "root = Card([CardHeader(\"a\", \"b\", \"c\", \"d\")])", + "expected": [ + { + "source": "parser", + "code": "excess-args", + "message": "CardHeader takes 2 arg(s), got 4 (2 excess dropped)", + "component": "CardHeader", + "statementId": "root" + } + ] + }, + { + "name": "type-mismatch", + "input": "root = Card([TextContent(42)])", + "expected": [ + { + "source": "parser", + "code": "type-mismatch", + "message": "field \"/text\" expects string but got number", + "component": "TextContent", + "path": "/text", + "statementId": "root" + } + ] + }, + { + "name": "several", + "input": "root = Card([a, b])\na = Foo()\nb = Button()", + "expected": [ + { + "source": "parser", + "code": "unknown-component", + "message": "Unknown component \"Foo\" — not found in catalog or builtins. Available components: Card, TextContent, MarkDownRenderer, CardHeader, Callout, TextCallout, CodeBlock, Image, ImageBlock, ImageGallery, Separator, HorizontalBarChart, Series, RadarChart, PieChart, RadialChart, SingleStackedBarChart, ScatterChart, ScatterSeries, Point, AreaChart, BarChart, LineChart, Table, Col, TagBlock, Form, Buttons, Button, FormControl, Input, TextArea, Select, SelectItem, DatePicker, Slider, CheckBoxGroup, CheckBoxItem, RadioGroup, RadioItem, Chips, ChipItem, Icon, OptionCards, OptionCard, IconButton, Steps, StepsItem, InlineHeader, EntityList, EditableTable, SnippetCardBlock, SnippetCardItem, IconText, ImageText, Text, BoldText, OverviewCardBlock, OverviewCardItem, MetricIndicatorInline, ContextCardBlock, ContextCardItem, Tag, CompositeCardBlock, CompositeCardItem, ImageTextLarge, ListBlock, ListItem, MetricIndicatorWithStrikethrough, VisualCardBlock, VisualCardItem, FollowUpBlock, FollowUpItem, SectionBlock, SectionItem, Tabs, TabItem, Accordion, AccordionItem, Carousel, Slice, Label, SwitchGroup, SwitchItem", + "component": "Foo", + "statementId": "a", + "hint": "Available components: Card, CardHeader, TextContent, MarkDownRenderer, Callout, TextCallout, Image, ImageBlock, ImageGallery, CodeBlock, Separator, Table, Col, BarChart, LineChart, AreaChart, RadarChart, HorizontalBarChart, Series, PieChart, RadialChart, SingleStackedBarChart, Slice, ScatterChart, ScatterSeries, Point, Form, FormControl, Label, Input, TextArea, Select, SelectItem, DatePicker, Slider, CheckBoxGroup, CheckBoxItem, RadioGroup, RadioItem, SwitchGroup, SwitchItem, Button, Buttons, ListBlock, ListItem, FollowUpBlock, FollowUpItem, SectionBlock, SectionItem, Tabs, TabItem, Accordion, AccordionItem, Steps, StepsItem, Carousel, TagBlock, Tag, EntityList, InlineHeader, Icon, IconButton, EditableTable, ChipItem, Chips, OptionCard, OptionCards, Text, BoldText, IconText, ImageText, ImageTextLarge, MetricIndicatorInline, MetricIndicatorWithStrikethrough, SnippetCardItem, SnippetCardBlock, OverviewCardItem, OverviewCardBlock, ContextCardItem, ContextCardBlock, CompositeCardItem, CompositeCardBlock, VisualCardItem, VisualCardBlock" + }, + { + "source": "parser", + "code": "missing-required", + "message": "missing required field \"/label\" — signature: Button(label*: string, action, variant: \"primary\"|\"secondary\"|\"tertiary\", type: \"normal\"|\"destructive\", size: \"extra-small\"|\"small\"|\"medium\"|\"large\")", + "component": "Button", + "path": "/label", + "statementId": "b", + "hint": "Signature: Button(label*, action, variant, type, size) — * marks required" + } + ] + } +] diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json index 35cbb7bbe2..e8cc871ec5 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json @@ -5655,5 +5655,54 @@ "queryStatements": [], "mutationStatements": [] } + }, + { + "name": "cloud-envelope", + "schema": "chat", + "input": "]]>openui:content?thesys=true\n```openui-lang\nroot = Card([h, t])\nh = CardHeader(\"Q3\", \"Revenue\")\nt = TextContent(\"Up 12%\")\n```\n]]>openui:end", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "CardHeader", + "props": { + "title": "Q3", + "subtitle": "Revenue" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "h" + }, + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Up 12%" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "t" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 3, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } } ] diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json index 13e2fb3269..7055727074 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json @@ -1 +1 @@ -[{"name":"chat-example-1","schema":"chat","input":"Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }","checkpoints":[{"at":607,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["highlights","statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1214,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1821,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","valu":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ov2","ov3","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":13,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2428,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[],"isFoldable":null},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secLandmarks","secFood","secWhen","f","actionBtns","src1","src2"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3035,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":null,"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["lm1tagIcon","lm2","lm3","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3642,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["lm3body","lm3tag","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":33,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"lm3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["foodCards","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4856,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Sh"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":45,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5463,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"P"},"partial":true,"hasDynamicProps":false,"statementId":"sp2"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sp3","tabSummer","actionBtns","src1","src2"],"orphaned":[],"statementCount":51,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6070,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Sein"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["su2","su3","actionBtns","src1","src2"],"orphaned":[],"statementCount":55,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6677,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":true,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":true,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{}},"partial":true,"hasDynamicProps":false,"statementId":"btn2"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btn3","src1","src2"],"orphaned":[],"statementCount":60,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7277,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":false,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"springList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":false,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":false,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":false,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":false,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{"type":"continue_conversation","context":"Show me the best hotels in Paris"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn2"},{"type":"element","typeName":"Button","props":{"label":"Build a Paris Itinerary","action":{"type":"continue_conversation","context":"Build a 5-day Paris itinerary for me"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn3"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[{"title":"Paris Travel Guide 2025","sourceName":"Travel and Tour World","url":"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/"},{"title":"Best Things to Do in Paris 2026","sourceName":"Time Out Paris","url":"http://www.timeout.fr/paris/en/for-tourists"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-2","schema":"chat","input":"Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")","checkpoints":[{"at":510,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpi1icon","kpi1rhs","kpi2","kpi3","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi1lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1020,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3icon","kpi3rhs","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":13,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi3lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1530,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabGrowth","t","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2040,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["retentio","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2550,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":35,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3060,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tab","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3570,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Sta"]},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":47,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4080,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":null,"body":[]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["supportIcon","supportMetric","supportChart","supportList","cardMarketing","actionButtons"],"orphaned":[],"statementCount":51,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"supportHeader"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4590,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","rig":null}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sup2","sup3","cardMarketing","actionButtons"],"orphaned":[],"statementCount":58,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["marketingMetric","marketingChart","marketingList","actionButtons"],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":true,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":true,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":true,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":true,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Co"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["mkt3","actionButtons"],"orphaned":[],"statementCount":70,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6118,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":false,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":false,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":false,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":false,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Cost per Lead","right":"$48.20","rightVariant":"number"},{"left":"Top Channel","right":"Organic Search","rightVariant":"text"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Break Down by Channel","action":{"type":"continue_conversation","context":"Break down this month's revenue by acquisition channel"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnChannels"},{"type":"element","typeName":"Button","props":{"label":"Forecast Next Quarter","action":{"type":"continue_conversation","context":"Forecast revenue and active users for next quarter"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnForecast"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionButtons"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":74,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-3","schema":"chat","input":"Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)","checkpoints":[{"at":361,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas"},"partial":true,"hasDynamicProps":false,"statementId":"header"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","inspoCards","form"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":722,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["i","insp2","form"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"insp1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1083,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2","form"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1444,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":null,"size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2icon","form"],"orphaned":[],"statementCount":11,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1805,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btnSkip","fcDestination","fcDates","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":15,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2166,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Fo","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":19,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2527,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tr1","tr2","tr3","tr4","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2888,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["oc2","oc3","oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":29,"errors":[{"code":"missing-required","component":"OptionCard","path":"/title","message":"missing required field \"/title\" — signature: OptionCard(value*: string, title*: string, subtitle: string, topContent, disabled: boolean)","statementId":"oc1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":34,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fcNotes"],"orphaned":[],"statementCount":39,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"fcStay"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3971,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":null},"partial":true,"hasDynamicProps":false,"statementId":"ch3"}],"rules":{},"defaultValue":["hotel"]},"partial":true,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":true,"hasDynamicProps":false,"statementId":"fcStay"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ch4","fcNotes"],"orphaned":[],"statementCount":46,"errors":[{"code":"missing-required","component":"Icon","path":"/name","message":"missing required field \"/name\" — signature: Icon(name*: string, category: string)","statementId":"ch3icon"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4322,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":false,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":false,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":{"type":"element","typeName":"Icon","props":{"name":"home","category":"home"},"partial":false,"hasDynamicProps":false,"statementId":"ch3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch3"},{"type":"element","typeName":"ChipItem","props":{"value":"camping","label":"Camping / Glamping","icon":{"type":"element","typeName":"Icon","props":{"name":"tent","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"ch4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch4"}],"rules":{},"defaultValue":["hotel"]},"partial":false,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fcStay"},{"type":"element","typeName":"FormControl","props":{"label":"Special Requests or Notes","input":{"type":"element","typeName":"TextArea","props":{"name":"special-requests","placeholder":"e.g. vegetarian meals, wheelchair access, honeymoon surprise...","rows":4},"partial":false,"hasDynamicProps":false,"statementId":"notesArea"},"hint":"Any dietary needs, accessibility requirements, or specific interests?"},"partial":false,"hasDynamicProps":false,"statementId":"fcNotes"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":50,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-4","schema":"chat","input":"Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }","checkpoints":[{"at":218,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Ene"},"partial":true,"hasDynamicProps":false,"statementId":"header"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":436,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to w"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":654,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["v1body","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"v1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":872,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":null,"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v1icon","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1090,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":null,"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v2tag","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1308,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["CompositeCard","src1","src2"],"orphaned":[],"statementCount":14,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1526,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1icon","t1body","t1tags","t1btn","t2","src1","src2"],"orphaned":[],"statementCount":16,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t1h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1744,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Wa"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2","src1","src2"],"orphaned":[],"statementCount":20,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1962,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2icon","t2body","t2tags","t2btn","src1","src2"],"orphaned":[],"statementCount":22,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t2h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":[]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2btn","src1","src2"],"orphaned":[],"statementCount":25,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2398,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceN":null}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2615,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":false,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":false,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},{"title":"Sajan Re (Official Music Video)","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=COUSCnFazzc"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-5","schema":"chat","input":"Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")","checkpoints":[{"at":37,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":74,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["title","tbl","followUps"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":111,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":""},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tbl","followUps"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":148,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":185,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs","users","followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":222,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Pyth"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years","followUps"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":259,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["years","followUps"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":296,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":333,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu1"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":370,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me m"},"partial":true,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu2"],"orphaned":[],"statementCount":8,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":407,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["FollowUpItem"],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":442,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"},{"type":"element","typeName":"FollowUpItem","props":{"text":"Show me a JavaScript comparison"},"partial":false,"hasDynamicProps":false,"statementId":"fu2"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"basic","schema":"test","input":"root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Bu"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Button","path":"/label","message":"missing required field \"/label\" — signature: Button(label*: string, action, variant: \"primary\"|\"secondary\")","statementId":"b1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-required","schema":"test","input":"root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["B"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Button"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":51,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"null-required-with-default","schema":"test","input":"root = Card([t1])\nt1 = Text(null)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"required-default-fills","schema":"test","input":"root = Card([x])\nx = Tagged(1, true, \"x\", null)","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tag"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":null,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-component","schema":"test","input":"root = Card([Mystery(\"a\"), Text(\"b\")])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mys"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mystery"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"excess-args","schema":"test","input":"root = Card([Text(\"a\", \"m\", \"extra\", 4)])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":41,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"type-mismatch-scalar","schema":"test","input":"root = Card([Text(42)], 7)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/title","message":"field \"/title\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-mismatch","schema":"test","input":"root = Card([Text(\"a\", \"xl\"), Button(\"b\", null, \"tertiary\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Button"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"terti"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"tertiary"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/size","message":"field \"/size\" expects one of [\"s\", \"m\", \"l\"] but got \"xl\"","statementId":"root"},{"code":"type-mismatch","component":"Button","path":"/variant","message":"field \"/variant\" expects one of [\"primary\", \"secondary\"] but got \"tertiary\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-partial-deferred","schema":"test","input":"root = Card([Text(\"a\", \"x","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"integer-boolean-const","schema":"test","input":"root = Card([x])\nx = Tagged(1.5, \"yes\", \"y\", \"loud\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tagg"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":{"k":"Member","obj":{"k":"Num","v":1},"field":"?"},"tone":"neutral"},"partial":true,"hasDynamicProps":true,"statementId":"x"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"loud"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"loud"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"},{"code":"type-mismatch","component":"Tagged","path":"/kind","message":"field \"/kind\" expects one of [\"x\"] but got \"y\"","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"nested-object","schema":"test","input":"root = Card([c1, c2, c3])\nc1 = Chart([\"a\"], [1], {unit: \"kg\"})\nc2 = Chart([\"a\"], [1], {scale: 2})\nc3 = Chart([\"a\"], [1], {unit: 5, scale: \"big\"})","checkpoints":[{"at":13,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c1","c2","c3"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"un":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":65,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":78,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":91,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scal":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c2"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":104,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":117,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":130,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":143,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":145,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c3"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"},{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"array-items-pruned","schema":"test","input":"root = Card([Chart([\"a\", 2, \"c\"], [1, \"x\", 3])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"element-in-data-slot","schema":"test","input":"root = Card([Chart([Text(\"a\")], [1])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unresolved-and-orphaned","schema":"test","input":"root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a","miss"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":58,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cycle","schema":"test","input":"root = Card([a])\na = Card([b])\nb = Card([a])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"b"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"self-reference","schema":"test","input":"root = Card([root])","checkpoints":[{"at":2,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["r"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["roo"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"no-root-first-component","schema":"test","input":"x = 1\nmain = Card([Text(\"a\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["main"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"main"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"root-name-statement","schema":"test","input":"Card = Card([Text(\"named\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"Card"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"n"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"duplicate-ids","schema":"test","input":"root = Card([a])\na = Text(\"first\")\na = Text(\"second\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fir"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":53,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"only-prose","schema":"test","input":"Here is your UI, it will appear below.","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"whitespace","schema":"test","input":" \n\t \n","checkpoints":[{"at":1,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fences-and-prose","schema":"test","input":"Sure! Here it is:\n```openui\nroot = Card([a])\na = Text(\"fenced\")\n```\nAnything else?","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"f"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":82,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiple-fences","schema":"test","input":"```\nroot = Card([a])\n```\nand\n```\na = Text(\"second block\")\n```","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"secon"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second bloc"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unclosed-fence","schema":"test","input":"```openui\nroot = Card([a])\na = Text(\"str","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"str"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fence-in-string","schema":"test","input":"root = Card([a])\na = Text(\"use ``` to fence\")","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"u"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use `"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` t"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fe"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"comments","schema":"test","input":"root = Card([a]) // trailing\n# full line\na = Text(\"not // a comment # here\")\n// done","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not /"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a com"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment #"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"crlf","schema":"test","input":"root = Card([a])\r\na = Text(\"windows\")\r\n","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"wind"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"string-escapes","schema":"test","input":"root = Card([a, b, c, d])\na = Text(\"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83d\\ude00\")\nb = Text('single \\' quote \\n esc \\q')\nc = Text(\"bad \\x escape\")\nd = Text(\"emoji 😀 and é and 漢字\")","checkpoints":[{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nqu"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ uni"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":112,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' qu"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":128,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x"},"partial":true,"hasDynamicProps":false,"statementId":"c"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["d"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":160,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":176,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":true,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and"},"partial":true,"hasDynamicProps":false,"statementId":"d"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":187,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and é and 漢字"},"partial":false,"hasDynamicProps":false,"statementId":"d"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"emoji-outside-strings","schema":"test","input":"root = Card([a]) 😀\na = Text(\"ok\") ✅","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-string","schema":"test","input":"root = Card([a])\na = Text(\"streaming tex","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"s"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"strea"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming tex"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-escape","schema":"test","input":"root = Card([a])\na = Text(\"ends with \\","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with \\"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"numbers","schema":"test","input":"root = Card([Chart([\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"], [-3, 1.5, 1e3, 007, -0, 2.5e-3])])\n$x = 1e\n$y = 1E+2\n$z = 3.","checkpoints":[{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Chart"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,0]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,{"k":"Member","obj":{"k":"Num","v":2},"field":"?"},null]},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":81,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$x":null},"queryStatements":[],"mutationStatements":[]}},{"at":99,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$x":null,"$y":100},"queryStatements":[],"mutationStatements":[]}},{"at":106,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$x":null,"$y":100,"$z":{"k":"Member","obj":{"k":"Num","v":3},"field":"?"}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"operators","schema":"test","input":"$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])","checkpoints":[{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$a":1},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":""}}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"ye"},"else":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":88,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":92,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiline-ternary","schema":"test","input":"$on = true\nroot = Card([t])\nt = Text($on\n ? \"enabled\"\n : \"disabled\")","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"StateRef","n":"$on"}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"en"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabl"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabled"}}},"partial":false,"hasDynamicProps":true,"statementId":"t"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}}]},{"name":"member-index","schema":"test","input":"$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"row":null}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":""}]}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":null,"?":null}]}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key":null}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"row"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":139,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key x"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"builtins","schema":"test","input":"$items = [3, 1, 2]\nroot = Card([Text(\"\" + @Count($items)), Text(\"\" + @Sum($items)), Text(@Round(2.555, 2) + \"\")])\nbare = Count($items)","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3]},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Count"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Count"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Su"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Su"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Comp","name":"Round","args":[]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":134,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"actions","schema":"test","input":"$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))","checkpoints":[{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Card"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1","b2","b3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Ac","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Ph","n":"ToAssistant"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ToAssistant","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":126,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Ph","n":"Res"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Res","b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":162,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["But"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Action"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":198,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https:"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":215,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https://openui.com"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b3"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}}]},{"name":"each","schema":"test","input":"$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))","checkpoints":[{"at":10,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[]},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a"}]},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["f","f"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"ti":null,"?":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b"}]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["Each"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ph","n":"t"}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[],"mappedProps":{}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":110,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":113,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"query-mutation","schema":"test","input":"$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])","checkpoints":[{"at":19,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["users"],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":57,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"Null"}],["?",{"k":"Null"}]]},"defaultsAST":null,"refreshAST":null,"deps":["$q"],"complete":true}],"mutationStatements":[]}},{"at":76,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":null,"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":95,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["save"],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":114,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"Null"}],["?",{"k":"Null"}]]}}]}},{"at":133,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":152,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"le"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":171,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["B"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":190,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Actio"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":209,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Ph","n":"Run"}]}]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Run"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":221,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"users","refType":"query"}]}]}]}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}}]},{"name":"state-query","schema":"test","input":"$data = Query(\"get\", {})\nroot = Card([Text(\"x\")])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Qu","Qu"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":null},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":""},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":25,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}}]},{"name":"inline-query","schema":"test","input":"root = Card([Text(Query(\"get\", {}))])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Qu"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":37,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"assignment","schema":"test","input":"$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Inpu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"na"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"excess-args","component":"Input","path":"","message":"Input takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$valu"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$valu":null},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$value"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$value":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"object-key-order","schema":"test","input":"$o = {b: 1, 2: \"two\", a: 3, 1: \"one\", \"10\": 10}\nroot = Card([Text(\"x\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{}},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"tw","b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"two","b":1,"a":null}},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":null,"2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":null,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-commas","schema":"test","input":"root = Card([Text(\"a\") Text(\"b\"), Text(\"c\"),])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":46,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"lowercase-builtin-name","schema":"test","input":"root = Card([Text(@first([1]))])","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fi"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["first"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-tokens","schema":"test","input":"root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"combining-characters","schema":"test","input":"root = Card([Text(\"e\\u0301 cafe\\u0301\"), Text(\"한국어\"), Text(\"ok\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u03"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é caf"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u0301 cafe\\u030"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-call","schema":"test","input":"root = Card([a, b])\na = Text(\"one\")\nb = Button(\"tw","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","b"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Butto"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Button","props":{"label":"tw"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-object","schema":"test","input":"root = Card([Chart([\"a\"], [1], {unit: \"k","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":null,"?":null}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"k"}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}] +[{"name":"chat-example-1","schema":"chat","input":"Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }","checkpoints":[{"at":607,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["highlights","statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1214,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1821,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","valu":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ov2","ov3","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":13,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2428,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[],"isFoldable":null},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secLandmarks","secFood","secWhen","f","actionBtns","src1","src2"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3035,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":null,"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["lm1tagIcon","lm2","lm3","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3642,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["lm3body","lm3tag","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":33,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"lm3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["foodCards","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4856,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Sh"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":45,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5463,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"P"},"partial":true,"hasDynamicProps":false,"statementId":"sp2"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sp3","tabSummer","actionBtns","src1","src2"],"orphaned":[],"statementCount":51,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6070,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Sein"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["su2","su3","actionBtns","src1","src2"],"orphaned":[],"statementCount":55,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6677,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":true,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":true,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{}},"partial":true,"hasDynamicProps":false,"statementId":"btn2"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btn3","src1","src2"],"orphaned":[],"statementCount":60,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7277,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":false,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"springList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":false,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":false,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":false,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":false,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{"type":"continue_conversation","context":"Show me the best hotels in Paris"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn2"},{"type":"element","typeName":"Button","props":{"label":"Build a Paris Itinerary","action":{"type":"continue_conversation","context":"Build a 5-day Paris itinerary for me"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn3"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[{"title":"Paris Travel Guide 2025","sourceName":"Travel and Tour World","url":"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/"},{"title":"Best Things to Do in Paris 2026","sourceName":"Time Out Paris","url":"http://www.timeout.fr/paris/en/for-tourists"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-2","schema":"chat","input":"Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")","checkpoints":[{"at":510,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpi1icon","kpi1rhs","kpi2","kpi3","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi1lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1020,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3icon","kpi3rhs","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":13,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi3lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1530,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabGrowth","t","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2040,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["retentio","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2550,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":35,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3060,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tab","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3570,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Sta"]},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":47,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4080,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":null,"body":[]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["supportIcon","supportMetric","supportChart","supportList","cardMarketing","actionButtons"],"orphaned":[],"statementCount":51,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"supportHeader"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4590,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","rig":null}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sup2","sup3","cardMarketing","actionButtons"],"orphaned":[],"statementCount":58,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["marketingMetric","marketingChart","marketingList","actionButtons"],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":true,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":true,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":true,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":true,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Co"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["mkt3","actionButtons"],"orphaned":[],"statementCount":70,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6118,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":false,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":false,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":false,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":false,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Cost per Lead","right":"$48.20","rightVariant":"number"},{"left":"Top Channel","right":"Organic Search","rightVariant":"text"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Break Down by Channel","action":{"type":"continue_conversation","context":"Break down this month's revenue by acquisition channel"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnChannels"},{"type":"element","typeName":"Button","props":{"label":"Forecast Next Quarter","action":{"type":"continue_conversation","context":"Forecast revenue and active users for next quarter"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnForecast"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionButtons"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":74,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-3","schema":"chat","input":"Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)","checkpoints":[{"at":361,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas"},"partial":true,"hasDynamicProps":false,"statementId":"header"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","inspoCards","form"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":722,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["i","insp2","form"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"insp1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1083,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2","form"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1444,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":null,"size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2icon","form"],"orphaned":[],"statementCount":11,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1805,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btnSkip","fcDestination","fcDates","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":15,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2166,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Fo","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":19,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2527,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tr1","tr2","tr3","tr4","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2888,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["oc2","oc3","oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":29,"errors":[{"code":"missing-required","component":"OptionCard","path":"/title","message":"missing required field \"/title\" — signature: OptionCard(value*: string, title*: string, subtitle: string, topContent, disabled: boolean)","statementId":"oc1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":34,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fcNotes"],"orphaned":[],"statementCount":39,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"fcStay"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3971,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":null},"partial":true,"hasDynamicProps":false,"statementId":"ch3"}],"rules":{},"defaultValue":["hotel"]},"partial":true,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":true,"hasDynamicProps":false,"statementId":"fcStay"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ch4","fcNotes"],"orphaned":[],"statementCount":46,"errors":[{"code":"missing-required","component":"Icon","path":"/name","message":"missing required field \"/name\" — signature: Icon(name*: string, category: string)","statementId":"ch3icon"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4322,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":false,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":false,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":{"type":"element","typeName":"Icon","props":{"name":"home","category":"home"},"partial":false,"hasDynamicProps":false,"statementId":"ch3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch3"},{"type":"element","typeName":"ChipItem","props":{"value":"camping","label":"Camping / Glamping","icon":{"type":"element","typeName":"Icon","props":{"name":"tent","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"ch4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch4"}],"rules":{},"defaultValue":["hotel"]},"partial":false,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fcStay"},{"type":"element","typeName":"FormControl","props":{"label":"Special Requests or Notes","input":{"type":"element","typeName":"TextArea","props":{"name":"special-requests","placeholder":"e.g. vegetarian meals, wheelchair access, honeymoon surprise...","rows":4},"partial":false,"hasDynamicProps":false,"statementId":"notesArea"},"hint":"Any dietary needs, accessibility requirements, or specific interests?"},"partial":false,"hasDynamicProps":false,"statementId":"fcNotes"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":50,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-4","schema":"chat","input":"Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }","checkpoints":[{"at":218,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Ene"},"partial":true,"hasDynamicProps":false,"statementId":"header"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":436,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to w"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":654,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["v1body","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"v1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":872,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":null,"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v1icon","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1090,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":null,"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v2tag","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1308,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["CompositeCard","src1","src2"],"orphaned":[],"statementCount":14,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1526,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1icon","t1body","t1tags","t1btn","t2","src1","src2"],"orphaned":[],"statementCount":16,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t1h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1744,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Wa"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2","src1","src2"],"orphaned":[],"statementCount":20,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1962,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2icon","t2body","t2tags","t2btn","src1","src2"],"orphaned":[],"statementCount":22,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t2h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":[]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2btn","src1","src2"],"orphaned":[],"statementCount":25,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2398,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceN":null}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2615,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":false,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":false,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},{"title":"Sajan Re (Official Music Video)","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=COUSCnFazzc"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-5","schema":"chat","input":"Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")","checkpoints":[{"at":37,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":74,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["title","tbl","followUps"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":111,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":""},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tbl","followUps"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":148,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":185,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs","users","followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":222,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Pyth"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years","followUps"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":259,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["years","followUps"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":296,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":333,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu1"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":370,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me m"},"partial":true,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu2"],"orphaned":[],"statementCount":8,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":407,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["FollowUpItem"],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":442,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"},{"type":"element","typeName":"FollowUpItem","props":{"text":"Show me a JavaScript comparison"},"partial":false,"hasDynamicProps":false,"statementId":"fu2"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"basic","schema":"test","input":"root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Bu"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Button","path":"/label","message":"missing required field \"/label\" — signature: Button(label*: string, action, variant: \"primary\"|\"secondary\")","statementId":"b1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-required","schema":"test","input":"root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["B"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Button"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":51,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"null-required-with-default","schema":"test","input":"root = Card([t1])\nt1 = Text(null)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"required-default-fills","schema":"test","input":"root = Card([x])\nx = Tagged(1, true, \"x\", null)","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tag"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":null,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-component","schema":"test","input":"root = Card([Mystery(\"a\"), Text(\"b\")])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mys"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mystery"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"excess-args","schema":"test","input":"root = Card([Text(\"a\", \"m\", \"extra\", 4)])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":41,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"type-mismatch-scalar","schema":"test","input":"root = Card([Text(42)], 7)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/title","message":"field \"/title\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-mismatch","schema":"test","input":"root = Card([Text(\"a\", \"xl\"), Button(\"b\", null, \"tertiary\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Button"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"terti"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"tertiary"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/size","message":"field \"/size\" expects one of [\"s\", \"m\", \"l\"] but got \"xl\"","statementId":"root"},{"code":"type-mismatch","component":"Button","path":"/variant","message":"field \"/variant\" expects one of [\"primary\", \"secondary\"] but got \"tertiary\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-partial-deferred","schema":"test","input":"root = Card([Text(\"a\", \"x","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"integer-boolean-const","schema":"test","input":"root = Card([x])\nx = Tagged(1.5, \"yes\", \"y\", \"loud\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tagg"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":{"k":"Member","obj":{"k":"Num","v":1},"field":"?"},"tone":"neutral"},"partial":true,"hasDynamicProps":true,"statementId":"x"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"loud"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"loud"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"},{"code":"type-mismatch","component":"Tagged","path":"/kind","message":"field \"/kind\" expects one of [\"x\"] but got \"y\"","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"nested-object","schema":"test","input":"root = Card([c1, c2, c3])\nc1 = Chart([\"a\"], [1], {unit: \"kg\"})\nc2 = Chart([\"a\"], [1], {scale: 2})\nc3 = Chart([\"a\"], [1], {unit: 5, scale: \"big\"})","checkpoints":[{"at":13,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c1","c2","c3"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"un":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":65,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":78,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":91,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scal":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c2"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":104,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":117,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":130,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":143,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":145,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c3"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"},{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"array-items-pruned","schema":"test","input":"root = Card([Chart([\"a\", 2, \"c\"], [1, \"x\", 3])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"element-in-data-slot","schema":"test","input":"root = Card([Chart([Text(\"a\")], [1])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unresolved-and-orphaned","schema":"test","input":"root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a","miss"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":58,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cycle","schema":"test","input":"root = Card([a])\na = Card([b])\nb = Card([a])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"b"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"self-reference","schema":"test","input":"root = Card([root])","checkpoints":[{"at":2,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["r"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["roo"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"no-root-first-component","schema":"test","input":"x = 1\nmain = Card([Text(\"a\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["main"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"main"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"root-name-statement","schema":"test","input":"Card = Card([Text(\"named\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"Card"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"n"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"duplicate-ids","schema":"test","input":"root = Card([a])\na = Text(\"first\")\na = Text(\"second\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fir"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":53,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"only-prose","schema":"test","input":"Here is your UI, it will appear below.","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"whitespace","schema":"test","input":" \n\t \n","checkpoints":[{"at":1,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fences-and-prose","schema":"test","input":"Sure! Here it is:\n```openui\nroot = Card([a])\na = Text(\"fenced\")\n```\nAnything else?","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"f"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":82,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiple-fences","schema":"test","input":"```\nroot = Card([a])\n```\nand\n```\na = Text(\"second block\")\n```","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"secon"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second bloc"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unclosed-fence","schema":"test","input":"```openui\nroot = Card([a])\na = Text(\"str","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"str"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fence-in-string","schema":"test","input":"root = Card([a])\na = Text(\"use ``` to fence\")","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"u"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use `"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` t"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fe"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"comments","schema":"test","input":"root = Card([a]) // trailing\n# full line\na = Text(\"not // a comment # here\")\n// done","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not /"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a com"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment #"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"crlf","schema":"test","input":"root = Card([a])\r\na = Text(\"windows\")\r\n","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"wind"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"string-escapes","schema":"test","input":"root = Card([a, b, c, d])\na = Text(\"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83d\\ude00\")\nb = Text('single \\' quote \\n esc \\q')\nc = Text(\"bad \\x escape\")\nd = Text(\"emoji 😀 and é and 漢字\")","checkpoints":[{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nqu"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ uni"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":112,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' qu"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":128,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x"},"partial":true,"hasDynamicProps":false,"statementId":"c"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["d"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":160,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":176,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":true,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and"},"partial":true,"hasDynamicProps":false,"statementId":"d"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":187,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and é and 漢字"},"partial":false,"hasDynamicProps":false,"statementId":"d"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"emoji-outside-strings","schema":"test","input":"root = Card([a]) 😀\na = Text(\"ok\") ✅","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-string","schema":"test","input":"root = Card([a])\na = Text(\"streaming tex","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"s"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"strea"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming tex"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-escape","schema":"test","input":"root = Card([a])\na = Text(\"ends with \\","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with \\"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"numbers","schema":"test","input":"root = Card([Chart([\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"], [-3, 1.5, 1e3, 007, -0, 2.5e-3])])\n$x = 1e\n$y = 1E+2\n$z = 3.","checkpoints":[{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Chart"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,0]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,{"k":"Member","obj":{"k":"Num","v":2},"field":"?"},null]},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":81,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$x":null},"queryStatements":[],"mutationStatements":[]}},{"at":99,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$x":null,"$y":100},"queryStatements":[],"mutationStatements":[]}},{"at":106,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$x":null,"$y":100,"$z":{"k":"Member","obj":{"k":"Num","v":3},"field":"?"}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"operators","schema":"test","input":"$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])","checkpoints":[{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$a":1},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":""}}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"ye"},"else":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":88,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":92,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiline-ternary","schema":"test","input":"$on = true\nroot = Card([t])\nt = Text($on\n ? \"enabled\"\n : \"disabled\")","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"StateRef","n":"$on"}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"en"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabl"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabled"}}},"partial":false,"hasDynamicProps":true,"statementId":"t"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}}]},{"name":"member-index","schema":"test","input":"$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"row":null}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":""}]}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":null,"?":null}]}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key":null}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"row"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":139,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key x"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"builtins","schema":"test","input":"$items = [3, 1, 2]\nroot = Card([Text(\"\" + @Count($items)), Text(\"\" + @Sum($items)), Text(@Round(2.555, 2) + \"\")])\nbare = Count($items)","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3]},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Count"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Count"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Su"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Su"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Comp","name":"Round","args":[]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":134,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"actions","schema":"test","input":"$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))","checkpoints":[{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Card"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1","b2","b3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Ac","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Ph","n":"ToAssistant"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ToAssistant","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":126,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Ph","n":"Res"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Res","b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":162,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["But"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Action"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":198,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https:"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":215,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https://openui.com"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b3"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}}]},{"name":"each","schema":"test","input":"$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))","checkpoints":[{"at":10,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[]},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a"}]},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["f","f"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"ti":null,"?":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b"}]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["Each"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ph","n":"t"}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[],"mappedProps":{}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":110,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":113,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"query-mutation","schema":"test","input":"$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])","checkpoints":[{"at":19,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["users"],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":57,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"Null"}],["?",{"k":"Null"}]]},"defaultsAST":null,"refreshAST":null,"deps":["$q"],"complete":true}],"mutationStatements":[]}},{"at":76,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":null,"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":95,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["save"],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":114,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"Null"}],["?",{"k":"Null"}]]}}]}},{"at":133,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":152,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"le"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":171,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["B"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":190,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Actio"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":209,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Ph","n":"Run"}]}]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Run"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":221,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"users","refType":"query"}]}]}]}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}}]},{"name":"state-query","schema":"test","input":"$data = Query(\"get\", {})\nroot = Card([Text(\"x\")])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Qu","Qu"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":null},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":""},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":25,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}}]},{"name":"inline-query","schema":"test","input":"root = Card([Text(Query(\"get\", {}))])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Qu"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":37,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"assignment","schema":"test","input":"$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Inpu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"na"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"excess-args","component":"Input","path":"","message":"Input takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$valu"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$valu":null},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$value"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$value":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"object-key-order","schema":"test","input":"$o = {b: 1, 2: \"two\", a: 3, 1: \"one\", \"10\": 10}\nroot = Card([Text(\"x\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{}},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"tw","b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"two","b":1,"a":null}},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":null,"2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":null,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-commas","schema":"test","input":"root = Card([Text(\"a\") Text(\"b\"), Text(\"c\"),])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":46,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"lowercase-builtin-name","schema":"test","input":"root = Card([Text(@first([1]))])","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fi"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["first"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-tokens","schema":"test","input":"root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"combining-characters","schema":"test","input":"root = Card([Text(\"e\\u0301 cafe\\u0301\"), Text(\"한국어\"), Text(\"ok\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u03"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é caf"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u0301 cafe\\u030"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-call","schema":"test","input":"root = Card([a, b])\na = Text(\"one\")\nb = Button(\"tw","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","b"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Butto"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Button","props":{"label":"tw"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-object","schema":"test","input":"root = Card([Chart([\"a\"], [1], {unit: \"k","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":null,"?":null}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"k"}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cloud-envelope","schema":"chat","input":"]]>openui:content?thesys=true\n```openui-lang\nroot = Card([h, t])\nh = CardHeader(\"Q3\", \"Revenue\")\nt = TextContent(\"Up 12%\")\n```\n]]>openui:end","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["h"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car","t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3"},"partial":true,"hasDynamicProps":false,"statementId":"h"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["TextCon"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":true,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":true,"hasDynamicProps":false,"statementId":"t"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":140,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}] diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 73477004f6..315b7ec224 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -161,6 +161,27 @@ import Testing RunLoop.main.run(until: Date().addingTimeInterval(0.3)) #expect(host.fittingSize.height > 200, "\(name) rendered \(host.fittingSize)") } + + @Test func passesParseResultsAndErrorsToTheHost() { + final class Received { + var parseResults = 0 + var errors: [[OpenUIError]] = [] + } + let received = Received() + let host = NSHostingView( + rootView: OpenUIRenderer( + response: "root = Card([Mystery(), TextContent(\"ok\")])", + library: OpenUIChatLibrary.library, + onParseResult: { _ in received.parseResults += 1 }, + onError: { received.errors.append($0) })) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 420, height: 300), styleMask: [.borderless], + backing: .buffered, defer: false) + window.contentView = host + RunLoop.main.run(until: Date().addingTimeInterval(0.3)) + #expect(received.parseResults == 1) + #expect(received.errors.map { $0.map(\.code) } == [["unknown-component"]]) + } } #endif From 8a42f34d2092eff87bf480443c56ed9bf660d953 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 00:55:32 +0530 Subject: [PATCH 08/52] test(swift-lang): cover query recovery and input identity end to end A failed query recovers on refetch and clears its error, and a rendered text field stays the same AppKit view while statements stream in after it and while typing writes its $binding (the focus loss found in the Angular port's review). --- .../OpenUILangTests/QueryAndFormTests.swift | 29 ++++++++++ .../OpenUISwiftUITests/RendererTests.swift | 53 +++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift b/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift index 3d59003ef2..4407bf016a 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift +++ b/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift @@ -40,6 +40,35 @@ import Testing #expect(manager.snapshot.errors.first?.hint == "Available tools: other") } + @Test func refetchRecoversFromAFailedQuery() async { + struct Unavailable: Error {} + final class Calls: @unchecked Sendable { var count = 0 } + let calls = Calls() + let manager = QueryManager( + toolProvider: FunctionToolProvider([ + "flaky": { _ in + calls.count += 1 + if calls.count == 1 { throw Unavailable() } + return ["ok": true] + } + ])) + manager.evaluateQueries([ + QueryNode( + statementId: "q", toolName: "flaky", args: [:], defaults: ["ok": false], + refreshInterval: nil, deps: nil, complete: true) + ]) + await settle() + #expect(manager.snapshot.errors.map(\.code) == ["tool-error"]) + #expect(manager.result("q") == ["ok": false]) + + manager.invalidate(["q"]) + #expect(manager.isLoading("q")) + await settle() + #expect(manager.snapshot.errors.isEmpty) + #expect(manager.result("q") == ["ok": true]) + #expect(calls.count == 2) + } + @Test func mutationSuccessAndFailure() async { let provider = FunctionToolProvider([ "save": { args in ["saved": args["name"] ?? .null] }, diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 315b7ec224..27c6bc2de7 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -162,6 +162,59 @@ import Testing #expect(host.fittingSize.height > 200, "\(name) rendered \(host.fittingSize)") } + /// The bug vishxrad hit in the Angular port: an input recreated on every + /// update loses focus mid-typing. The AppKit text field behind the SwiftUI + /// input must be the same object across streamed updates and typing. + @Test func keepsInputViewsAcrossStreamingAndTyping() { + final class Model: ObservableObject { + @Published var response = """ + $name = "" + root = Card([form, note]) + form = Form("f", btns, [field]) + btns = Buttons([Button("Save")]) + field = FormControl("Name", Input("name", "Your name", "text", null, $name)) + """ + var state = OpenUIObject() + } + struct Harness: View { + @ObservedObject var model: Model + var body: some View { + OpenUIRenderer( + response: model.response, isStreaming: true, library: OpenUIChatLibrary.library, + onStateUpdate: { model.state = $0 } + ) + .frame(width: 420) + } + } + func textFields(_ view: NSView) -> [NSTextField] { + let own = (view as? NSTextField).map { [$0] } ?? [] + return own + view.subviews.flatMap(textFields) + } + + let model = Model() + let host = NSHostingView(rootView: Harness(model: model)) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 420, height: 400), styleMask: [.borderless], + backing: .buffered, defer: false) + window.contentView = host + RunLoop.main.run(until: Date().addingTimeInterval(0.3)) + let field = textFields(host).first { $0.isEditable } + #expect(field != nil) + + // A later statement streams in after the field. + model.response += "\nnote = TextContent(\"Saved drafts appear here.\")" + RunLoop.main.run(until: Date().addingTimeInterval(0.3)) + #expect(textFields(host).first { $0.isEditable } === field) + + // Typing writes $name, which re-evaluates the tree. + field?.stringValue = "Ada" + field?.sendAction(field?.action, to: field?.target) + NotificationCenter.default.post(name: NSControl.textDidChangeNotification, object: field) + RunLoop.main.run(until: Date().addingTimeInterval(0.3)) + #expect(model.state["$name"] == "Ada") + #expect(textFields(host).first { $0.isEditable } === field) + } + @Test func passesParseResultsAndErrorsToTheHost() { final class Received { var parseResults = 0 From e3009cbf1e8a76ddab0c1b48cc64ff7ee64d26ac Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 00:58:12 +0530 Subject: [PATCH 09/52] feat(swift-lang): ship the chat prompt options and the schema generator ChatComponents now includes openuiChatPromptOptions (examples and additional rules), so a Swift app prompts exactly like a react-ui app: the full chat prompt and the chat Cloud config are byte-identical to react-ui's. ChatComponents.swift is generated from openuiChatLibrary by Scripts/generate-chat-components.mjs. --- .../Scripts/generate-chat-components.mjs | 176 ++++++++++++++++++ .../Sources/OpenUILang/ChatComponents.swift | 79 +++++++- .../OpenUILangTests/ChatComponentsTests.swift | 11 ++ .../OpenUILangTests/EditAndCloudTests.swift | 3 +- 4 files changed, 257 insertions(+), 12 deletions(-) create mode 100644 packages/swift-lang/Scripts/generate-chat-components.mjs diff --git a/packages/swift-lang/Scripts/generate-chat-components.mjs b/packages/swift-lang/Scripts/generate-chat-components.mjs new file mode 100644 index 0000000000..479026e41a --- /dev/null +++ b/packages/swift-lang/Scripts/generate-chat-components.mjs @@ -0,0 +1,176 @@ +// Regenerates Sources/OpenUILang/ChatComponents.swift from openuiChatLibrary in +// @openuidev/react-ui, so the Swift chat library can't drift from the web one. +// +// pnpm run build:packages +// node packages/swift-lang/Scripts/generate-chat-components.mjs +// +// The output is formatted with `swift format`. ChatComponentsTests checks the +// result against the fixtures from generate-fixtures.mjs. + +import { execFileSync } from "node:child_process"; +import { writeFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const here = dirname(fileURLToPath(import.meta.url)); +const packages = join(here, "..", ".."); +const output = join(here, "..", "Sources", "OpenUILang", "ChatComponents.swift"); + +// Code generation is not product usage, so keep lang-core's telemetry off. +process.env.OPENUI_TELEMETRY_DISABLED = "1"; + +const core = await import(join(packages, "lang-core", "dist", "index.mjs")); +const ui = await import(join(packages, "react-ui", "dist", "genui-lib", "index.mjs")); + +const library = ui.openuiChatLibrary; +const defs = library.toJSONSchema().$defs; +const spec = library.toSpec(); +const names = Object.keys(spec.components); +const known = new Set(names); + +// ── Swift literals ──────────────────────────────────────────────────────── + +function swiftString(text) { + const escaped = [...text] + .map((c) => { + if (c === "\\") return "\\\\"; + if (c === '"') return '\\"'; + if (c === "\n") return "\\n"; + if (c === "\r") return "\\r"; + if (c === "\t") return "\\t"; + const code = c.codePointAt(0); + return code < 0x20 ? `\\u{${code.toString(16)}}` : c; + }) + .join(""); + return `"${escaped}"`; +} + +function swiftValue(value) { + if (value === null) return ".null"; + if (Array.isArray(value)) return `[${value.map(swiftValue).join(", ")}]`; + if (typeof value === "object") { + const entries = Object.entries(value).map(([k, v]) => `${swiftString(k)}: ${swiftValue(v)}`); + return `[${entries.join(", ") || ":"}]`; + } + return typeof value === "string" ? swiftString(value) : JSON.stringify(value); +} + +// ── JSON Schema → PropType ──────────────────────────────────────────────── + +const isFormRules = (s) => + s?.type === "object" && s.properties && "minLength" in s.properties && "pattern" in s.properties; +const isActionExpression = (s) => + Array.isArray(s?.anyOf) && + s.anyOf.length === 3 && + s.anyOf[0].properties?.type?.const === "open_url"; + +function propType(s) { + if (isFormRules(s)) return "formRules"; + if (isActionExpression(s)) return ".actionExpression"; + if (s.$ref) return `.component(${swiftString(s.$ref.split("/").pop())})`; + if (s.anyOf) { + const options = s.anyOf.every((o) => o.$ref) + ? s.anyOf.filter((o) => known.has(o.$ref.split("/").pop())) + : s.anyOf; + return `.union([${options.map(propType).join(", ")}])`; + } + if (s.const !== undefined) return `.literal(${swiftValue(s.const)})`; + switch (s.type) { + case "string": + return s.enum ? `.enumeration([${s.enum.map(swiftString).join(", ")}])` : ".string"; + case "number": + case "integer": + return ".number"; + case "boolean": + return ".boolean"; + case "array": { + const minItems = s.minItems === undefined ? "" : `, minItems: ${s.minItems}`; + return `.array(${propType(s.items)}${minItems})`; + } + case "object": + if (s.propertyNames) return `.record(${propType(s.additionalProperties ?? {})})`; + return `.object([${props(s).join(", ")}])`; + default: + return ".any"; + } +} + +function props(schema, component) { + const required = schema.required ?? []; + const shape = component ? library.components[component].props.shape : {}; + return Object.entries(schema.properties ?? {}).map(([key, s]) => { + const args = [swiftString(key), propType(s)]; + if ("default" in s) args.push(`.defaulted(${swiftValue(s.default)})`); + else if (!required.includes(key)) args.push(".optional"); + if (shape[key] && core.isReactiveSchema(shape[key])) args.push("binding: true"); + if (s.description) args.push(`description: ${swiftString(s.description)}`); + return `Prop(${args.join(", ")})`; + }); +} + +// ── ChatComponents.swift ────────────────────────────────────────────────── + +const lowerFirst = (name) => name[0].toLowerCase() + name.slice(1); + +const schemas = names.map( + (name) => ` public static let ${lowerFirst(name)} = ComponentSchema( + ${swiftString(name)}, description: ${swiftString(defs[name].description ?? "")}, + props: [${props(defs[name], name).join(", ")}]) +`, +); + +const groups = spec.componentGroups.map((group) => { + const notes = group.notes?.length ? `, notes: [${group.notes.map(swiftString).join(", ")}]` : ""; + return ` ComponentGroup(name: ${swiftString(group.name)}, components: [${group.components.map(swiftString).join(", ")}]${notes}),`; +}); + +const { examples, additionalRules } = ui.openuiChatPromptOptions; + +writeFileSync( + output, + `// Generated by Scripts/generate-chat-components.mjs from openuiChatLibrary in +// @openuidev/react-ui. Don't edit by hand. +// swift-format-ignore-file: LineLength + +/// Schemas for the OpenUI chat library. Names, prop order, types and +/// descriptions match \`openuiChatLibrary\` in @openuidev/react-ui, so a backend +/// that prompts with either library produces responses both can render. +/// +/// The schemas live in \`OpenUILang\`, without SwiftUI, so a server can build +/// the chat prompt or Cloud config for them too. +public enum ChatComponents { + /// The structured \`rules\` object shared by form fields. + public static let formRules: PropType = .object( + ["required", "email", "url", "numeric"].map { Prop($0, .boolean, .optional) } + + ["min", "max", "minLength", "maxLength"].map { Prop($0, .number, .optional) } + + [Prop("pattern", .string, .optional)]) + +${schemas.join("\n")} + /// Prompt groups and notes, as in openuiChatLibrary. + public static let groups: [ComponentGroup] = [ +${groups.join("\n")} + ] + + /// Every schema, in library order. + public static let all: [ComponentSchema] = [ +${names.map((name) => ` ${lowerFirst(name)},`).join("\n")} + ] + + /// Example responses for the prompt (\`openuiChatExamples\`). + public static let examples: [String] = [ +${examples.map((example) => ` ${swiftString(example)},`).join("\n")} + ] + + /// Extra prompt rules for this library (\`openuiChatAdditionalRules\`). + public static let additionalRules: [String] = [ +${additionalRules.map((rule) => ` ${swiftString(rule)},`).join("\n")} + ] + + /// The prompt options react-ui pairs with this library (\`openuiChatPromptOptions\`). + public static let promptOptions = PromptOptions( + additionalRules: additionalRules, examples: examples) +} +`, +); +execFileSync("swift", ["format", "-i", output]); +console.log(`wrote ${names.length} chat component schemas to ${output}`); diff --git a/packages/swift-lang/Sources/OpenUILang/ChatComponents.swift b/packages/swift-lang/Sources/OpenUILang/ChatComponents.swift index 479577c25c..3120dd23bd 100644 --- a/packages/swift-lang/Sources/OpenUILang/ChatComponents.swift +++ b/packages/swift-lang/Sources/OpenUILang/ChatComponents.swift @@ -1,6 +1,13 @@ +// Generated by Scripts/generate-chat-components.mjs from openuiChatLibrary in +// @openuidev/react-ui. Don't edit by hand. +// swift-format-ignore-file: LineLength + /// Schemas for the OpenUI chat library. Names, prop order, types and /// descriptions match `openuiChatLibrary` in @openuidev/react-ui, so a backend /// that prompts with either library produces responses both can render. +/// +/// The schemas live in `OpenUILang`, without SwiftUI, so a server can build +/// the chat prompt or Cloud config for them too. public enum ChatComponents { /// The structured `rules` object shared by form fields. public static let formRules: PropType = .object( @@ -850,8 +857,7 @@ public enum ChatComponents { "- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card.", ]), ComponentGroup( - name: "Tables", - components: ["Table", "Col", "EditableTable"], + name: "Tables", components: ["Table", "Col", "EditableTable"], notes: [ "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.", @@ -865,8 +871,7 @@ public enum ChatComponents { name: "Charts (1D)", components: ["PieChart", "RadialChart", "SingleStackedBarChart", "Slice"]), ComponentGroup( - name: "Charts (Scatter)", - components: ["ScatterChart", "ScatterSeries", "Point"]), + name: "Charts (Scatter)", components: ["ScatterChart", "ScatterSeries", "Point"]), ComponentGroup( name: "Forms", components: [ @@ -884,8 +889,7 @@ public enum ChatComponents { "- The renderer shows error messages automatically — do NOT generate error text in the UI", ]), ComponentGroup( - name: "Buttons", - components: ["Button", "Buttons", "Icon", "IconButton"], + name: "Buttons", components: ["Button", "Buttons", "Icon", "IconButton"], notes: [ "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard." ]), @@ -900,8 +904,7 @@ public enum ChatComponents { "- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })", ]), ComponentGroup( - name: "Sections", - components: ["SectionBlock", "SectionItem"], + name: "Sections", components: ["SectionBlock", "SectionItem"], notes: [ "- SectionBlock renders collapsible accordion sections that auto-open as they stream.", "- Each section needs a unique `value` id, a `trigger` label, and a `content` array.", @@ -921,8 +924,7 @@ public enum ChatComponents { "- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs.", ]), ComponentGroup( - name: "Data Display", - components: ["TagBlock", "Tag", "EntityList"], + name: "Data Display", components: ["TagBlock", "Tag", "EntityList"], notes: [ "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not." ]), @@ -1032,4 +1034,61 @@ public enum ChatComponents { visualCardItem, visualCardBlock, ] + + /// Example responses for the prompt (`openuiChatExamples`). + public static let examples: [String] = [ + "Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }", + "Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")", + "Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)", + "Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }", + "Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")", + ] + + /// Extra prompt rules for this library (`openuiChatAdditionalRules`). + public static let additionalRules: [String] = [ + "When asked about data, generate realistic/plausible data", + "Every response is a single Card(children) — children stack vertically automatically. No layout params are needed on Card.", + "Card is the only layout container. Do NOT use Stack. Use Tabs to switch between sections, Carousel for horizontal scroll.", + "Use FollowUpBlock at the END of a Card to suggest what the user can do or ask next.", + "Use ListBlock when presenting a set of options or steps; give each ListItem an action (5th argument) to make it clickable — without one the item is plain text.", + "Use SectionBlock to group long responses into collapsible sections — good for reports, FAQs, and structured content.", + "Use SectionItem inside SectionBlock: each item needs a unique value id, a trigger (header label), and a content array.", + "Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])", + "IMPORTANT: Every slide in a Carousel must use the same component structure in the same order — e.g. all slides: [title, image, description, tags].", + "For forms, define one FormControl reference per field so controls can stream progressively.", + "For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).", + "Never nest Form inside Form.", + "CardHeader is the page-level heading — place it as the first child of Card; InlineHeader is a lighter subsection label for a block inside the response, and is redundant when the following component already has a heading.", + "Never use Callout or TextCallout to justify why you did what you did or for any meta-information.", + "Every image slot (Image, ImageBlock, ImageGallery, VisualCardItem/ContextCardItem bgImageSrc, ImageText, ImageTextLarge, ListItem image) requires a REAL URL from a tool result, the conversation, or the user — NEVER invent, guess, or template a URL.", + "If no image URL is in context, compose without image components — icons, gray ContextCardItems, and charts still make rich layouts.", + "Argument-order trap: Image takes alt FIRST, while ImageBlock, ImageText, and ImageTextLarge take src FIRST — alt text in a src slot ships a broken image.", + "Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items, all with the same structure; use layout \"grid\" for primary side-by-side comparison and \"carousel\" for secondary browsing.", + "The card-block action is BLOCK-LEVEL: one action shared by every card, with the clicked card's details attached automatically — keep continue_conversation context generic (e.g. \"Tell me more about this destination\"), and never use a block-level open_url since it would send every card to the same URL.", + "Card items have NO per-item action: to give each item its own external link, use CompositeCardItem with footer { button: Button(label, { type: \"open_url\", url }) } — never claim a card opens a link it cannot.", + "Text, BoldText, IconText, ImageText, ImageTextLarge and MetricIndicator* are inline building blocks used INSIDE card items — do not place them directly in the root Card.", + "EntityList size \"small\" is reserved for CompositeCardItem body content (no header/footer); use size \"default\" elsewhere.", + "Tag variant must be semantically correct (success=positive, danger=negative, warning=cautionary, info=informational, neutral=label); Tag takes an optional Icon second, so use Tag(text, icon, size, variant) when a variant is needed.", + "TagBlock takes plain strings — keep it to at most 3 tags.", + "ListBlock variant \"number\" is for ordered sequences and rankings, \"image\" for products/profiles with a real image; Steps is for ordered sequential processes only.", + "Use SectionBlock to divide a long response into independent, equally prominent topics; use Tabs when the items are alternative views of the same thing; set isFoldable=false unless a section has 4+ distinct blocks; never make SectionBlock the first Card child.", + "Accordion is for supplementary or FAQ content only — never primary information, 3-5 items max, and always the last component in its section or card.", + "Charts: LineChart/AreaChart variant \"natural\" for smooth trends and \"linear\" for precise point-to-point data; BarChart \"grouped\" for side-by-side comparison and \"stacked\" for part-to-whole; prefer HorizontalBarChart when category labels are long or numerous.", + "For large chart values, scale the data and put the unit in the axis label (e.g. yLabel \"Revenue ($k)\") instead of passing raw thousands or millions.", + "Quantitative asks get a chart (plus KPI cards where useful) in the FIRST response — do not answer numbers with prose or a table alone.", + "Table is column-oriented: each Col holds its own data array of plain strings or numbers (never components), and every column's array must have the same length.", + "Use EditableTable ONLY when the user or app explicitly asks for an editable table; default to Table for read-only data.", + "Every Form MUST have EXACTLY ONE submit Button with variant \"primary\" — that button validates the form; other buttons (secondary/tertiary escape hatches like \"Just Surprise Me\") skip validation, and there is never a reset button.", + "Prefer structured inputs (Select, Chips, OptionCards, DatePicker, Slider) over free-text Input, give every FormControl a clear label (and a hint where it prevents mistakes), and keep each field name unique within the response.", + "Validation rules ({ required: true, email: true, minLength: 8, ... }) are enforced with inline errors — use them for genuinely essential fields, but never require a free-text field where leaving it blank is meaningful.", + "Form inputs work ONLY inside a FormControl within a Form; for tappable suggestion choices OUTSIDE a form, use Buttons of continue_conversation Buttons — never a bare OptionCards or Chips.", + "Only add Buttons for real actions: form submit, open_url with a URL from a tool or the user (never fabricated), or a continue_conversation follow-up — never a button for an app action (open, download, export, edit) you cannot perform.", + "Every Button label must accurately describe what clicking it does; use \"primary\" for the main action and \"secondary\"/\"tertiary\" only for lower-emphasis supporting actions.", + "Icon: always include the category argument — it enables fallback matching when the exact lucide name is unavailable.", + "Pass sources on Card ONLY when the answer relies on real references you actually have, and cite them inline in TextContent as [1], [2] (1-based index into sources).", + ] + + /// The prompt options react-ui pairs with this library (`openuiChatPromptOptions`). + public static let promptOptions = PromptOptions( + additionalRules: additionalRules, examples: examples) } diff --git a/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift b/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift index aa3f5a42a2..2d04c3ecaa 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift +++ b/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift @@ -53,6 +53,17 @@ import Testing #expect(ChatComponents.groups == expected) } + @Test func chatLibraryPromptWithItsOptionsMatchesLangCore() { + // What react-ui apps send: openuiChatLibrary with openuiChatPromptOptions. + let fixture = FixtureCase.all("prompts").first { $0.name == "chat-options" }! + let library = Library( + components: ChatComponents.all.map { ComponentDefinition($0, content: ()) }, root: "Card", + componentGroups: ChatComponents.groups) + let prompt = library.prompt(ChatComponents.promptOptions) + let expected = fixture.value["expected"].stringValue! + #expect(prompt == expected, "\(firstLineDifference(prompt, expected) ?? "")") + } + @Test func chatLibraryPromptMatchesLangCore() { // The full chat prompt (no options) is one of the prompt fixtures. let fixture = FixtureCase.all("prompts").first { $0.name == "chat-default" }! diff --git a/packages/swift-lang/Tests/OpenUILangTests/EditAndCloudTests.swift b/packages/swift-lang/Tests/OpenUILangTests/EditAndCloudTests.swift index 3f76370862..2bc81951e7 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/EditAndCloudTests.swift +++ b/packages/swift-lang/Tests/OpenUILangTests/EditAndCloudTests.swift @@ -47,11 +47,10 @@ import Testing @Test func chatLibraryConfigMatchesLangCore() throws { // lang-core's config for openuiChatLibrary with its prompt options is // ~80 KB, so the fixture keeps its length and SHA-256. - let chatOptions = FixtureCase.all("prompts").first { $0.name == "chat-options" }!.value["spec"] let library = Library( components: ChatComponents.all.map { ComponentDefinition($0, content: ()) }, root: "Card", componentGroups: ChatComponents.groups) - let config = try library.cloudConfig(Self.promptOptions(chatOptions)) + let config = try library.cloudConfig(ChatComponents.promptOptions) let expected = Self.fixtures["chat"] #expect(Double(config.utf16.count) == expected["length"].numberValue) From 2095871e69d166e9a5eb57e42f073a0c9cbcd4ab Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 01:50:36 +0530 Subject: [PATCH 10/52] fix(swift-lang): match react-ui's component layouts and behavior Rendered every chat example and 42 real OpenUI Cloud responses with both react-ui (in Storybook, at the same width) and the SwiftUI renderer, and ported the differences: - Behavior: Tabs follow the streaming tab until the user picks one, Accordion opens the newest item, SectionBlock opens sections as they stream and folds back to the first when the response ends. - Layout: card blocks and OptionCards use react-ui's responsive grid (rows of up to 2 or 3, two columns at 768pt and below, one at 480pt), clickable cards get chevrons, snippet cards are label/value rows, visual cards put the text panel over the photo, and the root Card has no frame. - Text: TextContent renders full markdown with [n] citations resolved against the card's sources, tables, line breaks and $$ math (as source); only ~~double~~ tildes strike through. - Forms: required fields get an asterisk, DatePicker shows a placeholder until something is picked, Slider shows min/max labels, Select is a full-width field, switches lead their labels, and inputs use react-ui's field look. - Data: tables fill the width with tinted alternate rows, page like react-ui and show a placeholder while a Query fills them; FollowUpBlock shows "Related Queries"; sources show as favicon cards; tags use react-ui's corners and padding. - Charts: react-ui's default palette and curves (monotone by default, no point markers), horizontal grid lines, rounded bars, gradient area fills and scatter axes fitted to the data. Theme defaults follow react-ui's spacing, radii, fills and borders. --- .../Components/CardComponents.swift | 347 +++++++++++++----- .../Components/ChartComponents.swift | 118 +++++- .../Components/ContentComponents.swift | 86 ++++- .../Components/FormComponents.swift | 145 ++++++-- .../Components/IconComponents.swift | 19 +- .../Components/LayoutComponents.swift | 275 ++++++++++---- .../Components/SelectionComponents.swift | 84 +++-- .../Sources/OpenUISwiftUI/Support.swift | 190 +++++++++- .../Sources/OpenUISwiftUI/Theme.swift | 34 +- .../OpenUISwiftUITests/RendererTests.swift | 44 ++- 10 files changed, 1059 insertions(+), 283 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift index 5287972681..df7a7a6808 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift @@ -40,48 +40,140 @@ private func childString(_ node: OpenUIValue, _ key: String) -> String? { node.elementValue?.props[key]?.stringValue } +private struct TextAlignmentKey: EnvironmentKey { + static let defaultValue = TextAlignment.leading +} + +extension EnvironmentValues { + /// How text building blocks align, e.g. trailing in a snippet card's value column. + fileprivate var openUITextAlignment: TextAlignment { + get { self[TextAlignmentKey.self] } + set { self[TextAlignmentKey.self] = newValue } + } +} + // MARK: - Blocks -/// Lays out card items in a two-column grid or a horizontal carousel and makes -/// them clickable when the block has an action (and the response isn't streaming). +/// Card layout sizes from react-ui: small blocks use 280pt carousel cards, +/// medium ones 320pt (280pt in narrow blocks). +private enum CardBlockSize { + case small, medium +} + +/// react-ui's `getRowConfiguration`: how many cards go in each grid row. +func cardRowConfiguration(_ count: Int, maxPerRow: Int) -> [Int] { + if count <= 0 { return [] } + if count == 1 { return [1] } + if maxPerRow == 2 { + return Array(repeating: 2, count: count / 2) + (count % 2 == 1 ? [1] : []) + } + if count % 3 == 0 { return Array(repeating: 3, count: count / 3) } + if count % 3 == 2 { + var rows = Array(repeating: 3, count: count / 3) + rows.insert(2, at: (rows.count + 1) / 2) + return rows + } + return Array(repeating: 3, count: (count - 4) / 3) + [2, 2] +} + +/// Rows of up to `maxPerRow` cells, two columns in grids 768pt wide or less +/// (an odd last cell spans both) and one column at 480pt or less, like +/// react-ui's responsive card grids. Cells in a row share the tallest height. +struct ResponsiveCardGrid: View { + let count: Int + let maxPerRow: Int + var responsive = true + var spacing: CGFloat = 12 + @ViewBuilder let cell: (Int) -> Cell + @State private var width: CGFloat = 0 + + var body: some View { + VStack(spacing: spacing) { + ForEach(rows, id: \.self) { row in + HStack(alignment: .top, spacing: spacing) { + ForEach(row, id: \.self) { index in + cell(index).frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + } + } + .fixedSize(horizontal: false, vertical: true) + } + } + .frame(maxWidth: .infinity, alignment: .leading) + .onGeometryChange(for: CGFloat.self) { + $0.size.width + } action: { + width = $0 + } + } + + /// Cell indices per row. Until the width is known, one per row. + private var rows: [[Int]] { + let perRow: [Int] + if responsive && width <= 480 { + perRow = Array(repeating: 1, count: count) + } else if responsive && width <= 768 { + perRow = cardRowConfiguration(count, maxPerRow: 2) + } else { + perRow = cardRowConfiguration(count, maxPerRow: maxPerRow) + } + var start = 0 + return perRow.map { length in + defer { start += length } + return Array(start..: View { let props: ComponentProps + let size: CardBlockSize + let maxPerRow: Int let click: (Int, ComponentProps) -> (label: String, context: OpenUIObject) @ViewBuilder let item: (ComponentProps) -> Item + @State private var width: CGFloat = 0 @Environment(OpenUIContext.self) private var context @Environment(\.openUIFormName) private var form - @Environment(\.openUITheme) private var theme var body: some View { let items = props.children("items") - let gap = props.number("gap").map { CGFloat($0) } ?? theme.spacing + let gap = props.number("gap").map { CGFloat($0) } ?? 12 let clickable = props["action"].isTruthy && !context.isStreaming - if props.string("layout") == "carousel" { - ScrollView(.horizontal, showsIndicators: false) { - HStack(alignment: .top, spacing: gap) { - ForEach(Array(items.enumerated()), id: \.offset) { index, entry in - card(index, entry, clickable: clickable).frame(width: 240) + Group { + if props.string("layout") == "carousel" { + let cardWidth: CGFloat = size == .small || width <= 480 ? 280 : 320 + ScrollView(.horizontal, showsIndicators: false) { + HStack(alignment: .top, spacing: gap) { + ForEach(items.indices, id: \.self) { index in + card(index, items[index], clickable: clickable).frame(width: cardWidth) + } } + .padding(.vertical, 4) } - .padding(.vertical, 2) - } - } else { - let columns = props.bool("responsive") == false ? 2 : min(2, max(items.count, 1)) - LazyVGrid( - columns: Array( - repeating: GridItem(.flexible(), spacing: gap, alignment: .top), count: columns), - alignment: .leading, spacing: gap - ) { - ForEach(Array(items.enumerated()), id: \.offset) { index, entry in - card(index, entry, clickable: clickable) + } else { + ResponsiveCardGrid( + count: items.count, maxPerRow: maxPerRow, responsive: props.bool("responsive") != false, + spacing: gap + ) { index in + card(index, items[index], clickable: clickable) } } } + .frame(maxWidth: .infinity, alignment: .leading) + .onGeometryChange(for: CGFloat.self) { + $0.size.width + } action: { + width = $0 + } } @ViewBuilder private func card(_ index: Int, _ entry: ComponentProps, clickable: Bool) -> some View { - let content = item(entry).frame(maxWidth: .infinity, alignment: .topLeading) + let content = item(entry).environment(\.openUICardClickable, clickable) if clickable { Button { let (label, itemContext) = click(index, entry) @@ -97,26 +189,51 @@ private struct CardBlockLayout: View { } } -/// The bordered tile every card item sits on. -private struct CardTile: View { - var padding: CGFloat = 12 - var tint: Color? = nil - @ViewBuilder let content: Content - @Environment(\.openUITheme) private var theme +private struct CardClickableKey: EnvironmentKey { + static let defaultValue = false +} +extension EnvironmentValues { + /// Whether the card being drawn is clickable (its block has an action). + fileprivate var openUICardClickable: Bool { + get { self[CardClickableKey.self] } + set { self[CardClickableKey.self] = newValue } + } +} + +/// The chevron clickable cards show in a corner. +private struct CardChevron: View { + var size: CGFloat = 14 var body: some View { - VStack(alignment: .leading, spacing: 8) { content } - .padding(padding) - .frame(maxWidth: .infinity, alignment: .topLeading) - .background(tint ?? theme.surface, in: RoundedRectangle(cornerRadius: theme.cornerRadius)) - .overlay(RoundedRectangle(cornerRadius: theme.cornerRadius).strokeBorder(theme.border)) + Image(systemName: "chevron.right").font(.system(size: size * 0.8, weight: .semibold)) + } +} + +/// The small-card surface: faint fill when static, raised with an +/// interactive border and a light shadow when clickable. +private struct SmallCardSurface: ViewModifier { + let clickable: Bool + @Environment(\.openUITheme) private var theme + + func body(content: Content) -> some View { + content + .padding(10) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + .background( + clickable ? theme.surface : theme.subtleSurface, in: RoundedRectangle(cornerRadius: 14) + ) + .overlay( + RoundedRectangle(cornerRadius: 14).strokeBorder( + clickable ? theme.interactiveBorder : theme.border) + ) + .shadow(color: .black.opacity(clickable ? 0.05 : 0), radius: 2, y: 1) } } struct SnippetCardBlockView: View { let props: ComponentProps var body: some View { - CardBlockLayout(props: props) { index, item in + CardBlockLayout(props: props, size: .small, maxPerRow: 2) { index, item in let title = childString(item["lhs"], "title") return ( title ?? item.string("id") ?? "Snippet card \(index + 1)", @@ -139,40 +256,30 @@ struct SnippetCardItemView: View { var body: some View { SnippetCard(item: props) } } +/// One row: the label on the left, the value (or a chevron) on the right. private struct SnippetCard: View { let item: ComponentProps + @Environment(\.openUICardClickable) private var clickable var body: some View { - let value = compactValue - CardTile { - // Side by side when it fits; otherwise the value moves under the label - // rather than squeezing it into mid-word breaks. - ViewThatFits(in: .horizontal) { - HStack(alignment: .center, spacing: 8) { - OpenUINode(item["lhs"]).fixedSize(horizontal: true, vertical: false) - Spacer(minLength: 8) - OpenUINode(value).fixedSize() - } - VStack(alignment: .leading, spacing: 8) { - OpenUINode(item["lhs"]) - OpenUINode(value) - } + HStack(alignment: .center, spacing: 12) { + OpenUINode(item["lhs"]).frame(maxWidth: .infinity, alignment: .leading) + if !item["rhs"].isNullish { + OpenUINode(item["rhs"]) + .environment(\.openUITextAlignment, .trailing) + .fixedSize() + } else if clickable { + CardChevron().foregroundStyle(.secondary) } } - } - - /// The value sits small on the right, as in react-ui. - private var compactValue: OpenUIValue { - guard var rhs = item["rhs"].elementValue else { return item["rhs"] } - rhs.props["size"] = "xs" - return .element(rhs) + .modifier(SmallCardSurface(clickable: clickable)) } } struct OverviewCardBlockView: View { let props: ComponentProps var body: some View { - CardBlockLayout(props: props) { index, item in + CardBlockLayout(props: props, size: .small, maxPerRow: 3) { index, item in let title = childString(item["top"], "title") ?? childString(item["top"], "value") let subtitle = childString(item["top"], "subtitle") ?? childString(item["top"], "subtext") return ( @@ -195,20 +302,31 @@ struct OverviewCardItemView: View { var body: some View { OverviewCard(item: props) } } +/// A top slot (with the chevron) and a bottom metric, spread vertically. private struct OverviewCard: View { let item: ComponentProps + @Environment(\.openUICardClickable) private var clickable + var body: some View { - CardTile { - OpenUINode(item["top"]) - OpenUINode(item["bottom"]) + VStack(alignment: .leading, spacing: 0) { + HStack(alignment: .top, spacing: 8) { + OpenUINode(item["top"]).frame(maxWidth: .infinity, alignment: .leading) + if clickable { CardChevron().foregroundStyle(.secondary) } + } + .frame(minHeight: 24, alignment: .top) + if !item["bottom"].isNullish { + Spacer(minLength: 18) + OpenUINode(item["bottom"]) + } } + .modifier(SmallCardSurface(clickable: clickable)) } } struct ContextCardBlockView: View { let props: ComponentProps var body: some View { - CardBlockLayout(props: props) { index, item in + CardBlockLayout(props: props, size: .small, maxPerRow: 3) { index, item in let title = contextTitle(item) return ( title.isEmpty ? (item.string("id") ?? "Context card \(index + 1)") : title, @@ -238,47 +356,59 @@ private func contextTitle(_ item: ComponentProps) -> String { } } -/// A compact tinted card, or a photo card with a scrim when it has a -/// background image. +/// A small title (or Tag) at the top and bold body text at the bottom, on a +/// tinted fill or a darkened photo. private struct ContextCard: View { let item: ComponentProps + @Environment(\.openUICardClickable) private var clickable @Environment(\.openUITheme) private var theme var body: some View { let image = item.string("bgImageSrc").flatMap { $0.isEmpty ? nil : $0 } - VStack(alignment: .leading, spacing: 6) { - if case .element = item["title"] { - OpenUINode(item["title"]) - } else { - Text(item.text("title")).font(.subheadline).opacity(0.75) + VStack(alignment: .leading, spacing: 0) { + HStack(alignment: .top, spacing: 8) { + Group { + if case .element = item["title"] { + OpenUINode(item["title"]).environment(\.openUITagOnImage, image != nil) + } else { + Text(item.text("title")).font(.subheadline) + .foregroundStyle( + image == nil ? AnyShapeStyle(.secondary) : AnyShapeStyle(.white.opacity(0.8))) + } + } + .frame(maxWidth: .infinity, alignment: .leading) + if clickable { CardChevron(size: 16) } } + .frame(minHeight: 24, alignment: .top) + Spacer(minLength: 18) if let body = item.string("body"), !body.isEmpty { - Text(body).font(.headline) + Text(body).font(.body.weight(.semibold)) } } .padding(12) - .frame(maxWidth: .infinity, minHeight: image == nil ? nil : 130, alignment: .bottomLeading) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) .foregroundStyle(image == nil ? Color.primary : Color.white) .background { if let image { RemoteImage(src: image, alt: item.text("bgImageAlt")) .overlay( LinearGradient( - colors: [.black.opacity(0.1), .black.opacity(0.7)], startPoint: .top, + colors: [.black.opacity(0.25), .black.opacity(0.65)], startPoint: .top, endPoint: .bottom)) + } else if clickable || item.string("bgColor") == "gray" { + theme.sunkSurface } else { - item.string("bgColor") == "gray" ? theme.sunkSurface : theme.surface + theme.subtleSurface } } - .clipShape(RoundedRectangle(cornerRadius: theme.cornerRadius)) - .overlay(RoundedRectangle(cornerRadius: theme.cornerRadius).strokeBorder(theme.border)) + .clipShape(RoundedRectangle(cornerRadius: 12)) } } struct CompositeCardBlockView: View { let props: ComponentProps var body: some View { - CardBlockLayout(props: props) { index, item in + CardBlockLayout(props: props, size: .medium, maxPerRow: 2) { index, item in let header = item["header"].elementValue?.props ?? OpenUIObject() func pick(_ keys: String...) -> String? { keys.lazy.compactMap { header[$0]?.stringValue }.first @@ -310,28 +440,39 @@ struct CompositeCardItemView: View { var body: some View { CompositeCard(item: props) } } +/// Header, stacked body content, and a price-over-button footer. private struct CompositeCard: View { let item: ComponentProps + @Environment(\.openUICardClickable) private var clickable + @Environment(\.openUITheme) private var theme + var body: some View { - CardTile { + VStack(alignment: .leading, spacing: 12) { OpenUINode(item["header"]) - OpenUINodes(item.array("body"), spacing: 8) + OpenUINodes(item.array("body"), spacing: 12) let footer = item["footer"] if !footer["price"].isNullish || !footer["button"].isNullish { - HStack(alignment: .center) { + VStack(alignment: .leading, spacing: 8) { OpenUINode(footer["price"]) - Spacer(minLength: 8) - OpenUINode(footer["button"]) + OpenUINode(footer["button"]).environment(\.openUIButtonFillsWidth, true) } } } + .padding(12) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + .background( + clickable ? theme.surface : theme.subtleSurface, in: RoundedRectangle(cornerRadius: 16) + ) + .overlay( + RoundedRectangle(cornerRadius: 16).strokeBorder( + clickable ? theme.interactiveBorder : theme.border)) } } struct VisualCardBlockView: View { let props: ComponentProps var body: some View { - CardBlockLayout(props: props) { index, item in + CardBlockLayout(props: props, size: .medium, maxPerRow: 3) { index, item in let bodyValue = item["body"].elementValue?.props["value"]?.stringValue let tagText = item["tag"].elementValue?.props["text"]?.stringValue let label = [bodyValue, tagText, item.string("id")].compactMap { $0 }.first { !$0.isEmpty } @@ -356,26 +497,47 @@ struct VisualCardItemView: View { var body: some View { VisualCard(item: props) } } -/// A photo-first card: full-bleed image, tag on top, bold text panel below. +/// A photo-first card: the image fills the card, the tag and chevron sit on +/// top, and the text panel floats over the bottom of the photo. private struct VisualCard: View { let item: ComponentProps + @Environment(\.openUICardClickable) private var clickable @Environment(\.openUITheme) private var theme var body: some View { VStack(alignment: .leading, spacing: 0) { - RemoteImage(src: item.string("bgImageSrc"), alt: item.text("bgImageAlt")) - .frame(height: 140) - .clipped() - .overlay(alignment: .topLeading) { - OpenUINode(item["tag"]) - .environment(\.openUITagOnImage, true) - .padding(8) + HStack(alignment: .top) { + OpenUINode(item["tag"]).environment(\.openUITagOnImage, true) + Spacer(minLength: 8) + if clickable { + CardChevron(size: 16) + .foregroundStyle(.white) + .padding(4) + .background(.black.opacity(0.4), in: RoundedRectangle(cornerRadius: 6)) } - OpenUINode(item["body"]).padding(12) + } + .frame(minHeight: 24, alignment: .top) + .padding(12) + Spacer(minLength: 0) + if !item["body"].isNullish { + OpenUINode(item["body"]) + .padding(.vertical, 8) + .padding(.horizontal, 10) + .frame(maxWidth: .infinity, alignment: .leading) + .background(theme.surface, in: RoundedRectangle(cornerRadius: 10)) + .overlay(RoundedRectangle(cornerRadius: 10).strokeBorder(theme.border)) + .padding([.horizontal, .bottom], 12) + } } - .background(theme.surface) - .clipShape(RoundedRectangle(cornerRadius: theme.cornerRadius)) - .overlay(RoundedRectangle(cornerRadius: theme.cornerRadius).strokeBorder(theme.border)) + .frame(maxWidth: .infinity, minHeight: 280, maxHeight: .infinity, alignment: .topLeading) + .background { + ZStack { + theme.subtleSurface + RemoteImage(src: item.string("bgImageSrc"), alt: item.text("bgImageAlt")) + } + } + .clipShape(RoundedRectangle(cornerRadius: 16)) + .overlay(RoundedRectangle(cornerRadius: 16).strokeBorder(theme.border)) } } @@ -386,9 +548,10 @@ private struct VisualCard: View { struct TextLineView: View { let props: ComponentProps let bold: Bool + @Environment(\.openUITextAlignment) private var alignment var body: some View { - VStack(alignment: .leading, spacing: 2) { + VStack(alignment: alignment == .trailing ? .trailing : .leading, spacing: 2) { Text(props.text("value")) .font(font.weight(bold ? .semibold : .regular)) .monospacedDigit(props.string("variant") == "number") diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift index bc94be63aa..a309880864 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift @@ -32,11 +32,65 @@ private func labelOrder(_ props: ComponentProps) -> [String] { return props.array("labels").map(displayText).filter { seen.insert($0).inserted } } +/// react-ui's `seriesCurve`: "linear", "step", and anything else (including a +/// value still streaming in) is the default "natural", a monotone curve. private func interpolation(_ variant: String?) -> InterpolationMethod { switch variant { - case "natural": return .monotone + case "linear": return .linear case "step": return .stepCenter - default: return .linear + default: return .monotone + } +} + +/// react-ui's default chart palette (OCEAN_DEFAULT), with colors picked from +/// the middle of the ramp outwards like its `getDistributedColors`. +enum ChartPalette { + static let ocean: [Color] = [ + 0x0D47A1, 0x1565C0, 0x1976D2, 0x1E88E5, 0x2196F3, 0x42A5F5, 0x64B5F6, 0x90CAF9, 0xBBDEFB, + 0xE3F2FD, 0xEFF8FF, + ].map(color) + + private static func color(_ hex: Int) -> Color { + let red = Double((hex >> 16) & 0xFF) / 255 + let green = Double((hex >> 8) & 0xFF) / 255 + let blue = Double(hex & 0xFF) / 255 + return Color(red: red, green: green, blue: blue) + } + + static func colors(_ count: Int) -> [Color] { + let n = ocean.count + let mid = n / 2 + switch count { + case ...0: return [] + case 1: return [ocean[mid]] + case 2: return [ocean[max(mid - 1, 0)], ocean[min(mid + 1, n - 1)]] + default: + let offset = (count - 1) / 2 + return (0.. [String] { + var seen: Set = [] + return props.children("series").map { $0.text("category") }.filter { seen.insert($0).inserted } +} + +extension View { + /// Colors chart series with react-ui's palette. + fileprivate func paletteScale(_ names: [String]) -> some View { + chartForegroundStyleScale(domain: names, range: ChartPalette.colors(names.count)) + } + + /// Horizontal grid lines only, as react-ui's cartesian charts draw them. + fileprivate func categoryAxisWithoutGrid() -> some View { + chartXAxis { + AxisMarks { _ in + AxisTick() + AxisValueLabel() + } + } } } @@ -72,9 +126,12 @@ struct BarChartView: View { BarMark(x: .value("Label", point.label), y: .value("Value", point.value)) .foregroundStyle(by: .value("Series", point.series)) .position(by: .value("Series", point.series)) + .cornerRadius(4) } } .chartXScale(domain: labelOrder(props)) + .paletteScale(seriesNames(props)) + .categoryAxisWithoutGrid() .chartXAxisLabel(props.text("xLabel")) .chartYAxisLabel(props.text("yLabel")) } @@ -101,9 +158,11 @@ struct HorizontalBarChartView: View { ) .foregroundStyle(by: .value("Series", point.series)) .position(by: .value("Series", point.series)) + .cornerRadius(4) } } .chartYScale(domain: labels) + .paletteScale(seriesNames(props)) .chartYAxis { AxisMarks(preset: .aligned, position: .leading) { _ in AxisValueLabel(horizontalSpacing: 8) @@ -126,11 +185,11 @@ struct LineChartView: View { LineMark(x: .value("Label", point.label), y: .value("Value", point.value)) .foregroundStyle(by: .value("Series", point.series)) .interpolationMethod(method) - PointMark(x: .value("Label", point.label), y: .value("Value", point.value)) - .foregroundStyle(by: .value("Series", point.series)) - .symbolSize(18) + .lineStyle(StrokeStyle(lineWidth: 2)) } .chartXScale(domain: labelOrder(props)) + .paletteScale(seriesNames(props)) + .categoryAxisWithoutGrid() .chartXAxisLabel(props.text("xLabel")) .chartYAxisLabel(props.text("yLabel")) } @@ -142,20 +201,29 @@ struct AreaChartView: View { var body: some View { let method = interpolation(props.string("variant")) + let names = seriesNames(props) + let colors = ChartPalette.colors(names.count) ChartFrame(props) { Chart(seriesPoints(props)) { point in + let color = colors[names.firstIndex(of: point.series) ?? 0] + // react-ui fills areas with a gradient from 60% opacity to clear. AreaMark( x: .value("Label", point.label), y: .value("Value", point.value), - stacking: .unstacked + series: .value("Series", point.series), stacking: .unstacked + ) + .foregroundStyle( + LinearGradient( + colors: [color.opacity(0.6), color.opacity(0)], startPoint: .top, endPoint: .bottom) ) - .foregroundStyle(by: .value("Series", point.series)) - .opacity(0.25) .interpolationMethod(method) LineMark(x: .value("Label", point.label), y: .value("Value", point.value)) .foregroundStyle(by: .value("Series", point.series)) .interpolationMethod(method) + .lineStyle(StrokeStyle(lineWidth: 2)) } .chartXScale(domain: labelOrder(props)) + .chartForegroundStyleScale(domain: names, range: colors) + .categoryAxisWithoutGrid() .chartXAxisLabel(props.text("xLabel")) .chartYAxisLabel(props.text("yLabel")) } @@ -202,6 +270,9 @@ struct PieChartView: View { .foregroundStyle(.clear) } } + .chartForegroundStyleScale( + domain: data.map(\.label), range: ChartPalette.colors(data.count) + ) .chartLegend(position: .bottom, alignment: .leading) .rotationEffect(semi ? .degrees(-90) : .zero) .frame(height: theme.chartHeight) @@ -214,6 +285,7 @@ struct RadialChartView: View { var body: some View { let data = slices(props) + let colors = ChartPalette.colors(props.array("values").count) let maximum = max(data.map(\.value).max() ?? 1, 1) HStack(spacing: theme.spacing) { ZStack { @@ -224,7 +296,7 @@ struct RadialChartView: View { .padding(inset) Circle() .trim(from: 0, to: slice.value / maximum * 0.75) - .stroke(Self.color(slice.id), style: StrokeStyle(lineWidth: 10, lineCap: .round)) + .stroke(colors[slice.id], style: StrokeStyle(lineWidth: 10, lineCap: .round)) .rotationEffect(.degrees(-90)) .padding(inset) } @@ -233,7 +305,7 @@ struct RadialChartView: View { VStack(alignment: .leading, spacing: 4) { ForEach(data) { slice in HStack(spacing: 6) { - Circle().fill(Self.color(slice.id)).frame(width: 8, height: 8) + Circle().fill(colors[slice.id]).frame(width: 8, height: 8) Text(slice.label).font(.caption) Text(jsNumberToString(slice.value)).font(.caption.monospacedDigit()) .foregroundStyle(.secondary) @@ -243,18 +315,20 @@ struct RadialChartView: View { } } - static let palette: [Color] = [.blue, .green, .orange, .purple, .pink, .teal, .yellow, .red] - static func color(_ index: Int) -> Color { palette[index % palette.count] } } struct SingleStackedBarChartView: View { let props: ComponentProps var body: some View { - Chart(slices(props)) { slice in + let data = slices(props) + Chart(data) { slice in BarMark(x: .value("Value", slice.value), y: .value("Total", "")) .foregroundStyle(by: .value("Label", slice.label)) } + .chartForegroundStyleScale( + domain: data.map(\.label), range: ChartPalette.colors(data.count) + ) .chartYAxis(.hidden) .chartLegend(position: .bottom, alignment: .leading) .frame(height: 80) @@ -282,16 +356,30 @@ struct ScatterChartView: View { Dot(id: dots.count, series: dataset.text("name"), x: x, y: y, z: point.number("z"))) } } + let names = props.children("datasets").map { $0.text("name") } return Chart(dots) { dot in PointMark(x: .value(props.text("xLabel"), dot.x), y: .value(props.text("yLabel"), dot.y)) .foregroundStyle(by: .value("Series", dot.series)) .symbolSize(dot.z.map { max(20, min($0, 400)) } ?? 40) } + .chartXScale(domain: Self.domain(dots.map(\.x))) + .chartYScale(domain: Self.domain(dots.map(\.y))) + .chartForegroundStyleScale(domain: names, range: ChartPalette.colors(names.count)) .chartXAxisLabel(props.text("xLabel")) .chartYAxisLabel(props.text("yLabel")) .chartLegend(position: .bottom, alignment: .leading) .frame(height: theme.chartHeight) } + + /// react-ui's `calculateScatterDomain`: the data range padded by 10% on each + /// side, never below zero. + static func domain(_ values: [Double]) -> ClosedRange { + guard let low = values.min(), let high = values.max() else { return 0...100 } + let padding = (high - low) * 0.1 + let start = max(0, low - padding) + let end = high + padding + return end > start ? start...end : start...(start + 1) + } } /// Spider chart: one axis per label, one filled polygon per series. Swift @@ -344,7 +432,7 @@ struct RadarChartView: View { $0 < entry.values.count ? entry.values[$0] / maximum : 0 } let shape = polygon(fractions) - let color = RadialChartView.color(index) + let color = ChartPalette.colors(series.count)[index] context.fill(shape, with: .color(color.opacity(0.18))) context.stroke(shape, with: .color(color), lineWidth: 2) } @@ -353,7 +441,7 @@ struct RadarChartView: View { FlowLayout(spacing: 12) { ForEach(Array(series.enumerated()), id: \.offset) { index, entry in HStack(spacing: 6) { - Circle().fill(RadialChartView.color(index)).frame(width: 8, height: 8) + Circle().fill(ChartPalette.colors(series.count)[index]).frame(width: 8, height: 8) Text(entry.name).font(.caption).foregroundStyle(.secondary) } } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift index 231d21ee91..7cd4a6d45f 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift @@ -8,44 +8,90 @@ struct CardView: View { @Environment(\.openUITheme) private var theme var body: some View { + let sources = props.array("sources") VStack(alignment: .leading, spacing: theme.spacing) { OpenUINodes(props.array("children")) - let sources = props.array("sources") if !sources.isEmpty { SourcesStrip(sources: sources) } } .frame(maxWidth: .infinity, alignment: .leading) .surface("card") + .environment(\.openUICardSources, sources) } } /// Numbered references cited inline as [1], [2] in the card's text. private struct SourcesStrip: View { let sources: [OpenUIValue] - @Environment(\.openUITheme) private var theme var body: some View { - VStack(alignment: .leading, spacing: theme.compactSpacing) { - Divider() - Text("Sources").font(.caption.weight(.semibold)).foregroundStyle(.secondary) - ForEach(Array(sources.enumerated()), id: \.offset) { index, source in - let title = displayText(source["title"]) - let name = displayText(source["sourceName"]) - HStack(alignment: .firstTextBaseline, spacing: 6) { - Text("[\(index + 1)]").font(.caption.monospacedDigit()).foregroundStyle(.secondary) - if let url = source["url"].stringValue.flatMap(URL.init(string:)) { - Link(title, destination: url).font(.caption) - } else { - Text(title).font(.caption) + VStack(alignment: .leading, spacing: 8) { + Text("Sources").font(.subheadline.weight(.medium)).foregroundStyle(.secondary) + ScrollView(.horizontal, showsIndicators: false) { + HStack(alignment: .top, spacing: 12) { + ForEach(sources.indices, id: \.self) { index in + SourceCard(source: sources[index]) } - if !name.isEmpty { Text(name).font(.caption).foregroundStyle(.secondary) } } } } } } +/// One source, like react-ui's listed source: favicon and site name, then the +/// title. Opens the source when it has a URL. +private struct SourceCard: View { + let source: OpenUIValue + @Environment(\.openUITheme) private var theme + + var body: some View { + let url = source["url"].stringValue.flatMap(URL.init(string:)) + let card = VStack(alignment: .leading, spacing: 4) { + HStack(spacing: 8) { + Favicon(host: url?.host()) + Text(displayText(source["sourceName"])).font(.caption.weight(.medium)).lineLimit(1) + } + Text(displayText(source["title"])) + .font(.caption) + .foregroundStyle(.secondary) + .lineLimit(2) + .multilineTextAlignment(.leading) + } + .padding(8) + .frame(width: 180, alignment: .topLeading) + .overlay(RoundedRectangle(cornerRadius: 10).strokeBorder(theme.border)) + if let url { + Link(destination: url) { card }.buttonStyle(.plain) + } else { + card + } + } +} + +/// A site's favicon from Google's favicon service, as react-ui uses, with a +/// globe while it loads or when there's no URL. +private struct Favicon: View { + let host: String? + + var body: some View { + Group { + if let host, let url = URL(string: "https://www.google.com/s2/favicons?sz=128&domain=\(host)") + { + AsyncImage(url: url) { image in + image.resizable().scaledToFit() + } placeholder: { + Image(systemName: "globe").foregroundStyle(.secondary) + } + } else { + Image(systemName: "globe").foregroundStyle(.secondary) + } + } + .frame(width: 20, height: 20) + .clipShape(RoundedRectangle(cornerRadius: 4)) + } +} + struct CardHeaderView: View { let props: ComponentProps @@ -67,7 +113,8 @@ struct TextContentView: View { let props: ComponentProps var body: some View { - InlineMarkdown(props.text("text")) + // Full markdown with citations, like react-ui's TextContentWrapper. + MarkdownBlocks(props.text("text"), citations: true) .font(font) .frame(maxWidth: .infinity, alignment: .leading) } @@ -312,12 +359,11 @@ struct TagBlockView: View { var body: some View { FlowLayout(spacing: theme.compactSpacing) { ForEach(Array(props.array("tags").enumerated()), id: \.offset) { _, tag in + let size = props.string("size") Text(displayText(tag)) .font(font) - .padding(.horizontal, 8) - .padding(.vertical, 3) - .background(theme.sunkSurface, in: Capsule()) - .overlay(Capsule().strokeBorder(theme.border)) + .padding(tagPadding(size)) + .background(theme.sunkSurface, in: RoundedRectangle(cornerRadius: tagRadius(size))) } } } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift index d70feda066..f82e1ab157 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift @@ -23,12 +23,14 @@ struct FormControlView: View { @Environment(FormValidation.self) private var validation: FormValidation? var body: some View { - let fieldName = props.children("input").first?.string("name") + let input = props.children("input").first + let fieldName = input?.string("name") + let required = input?["rules"]["required"] == true VStack(alignment: .leading, spacing: 6) { - Text(props.text("label")).font(.subheadline.weight(.medium)) + Text(props.text("label") + (required ? "*" : "")).font(.subheadline.weight(.medium)) OpenUINode(props["input"]) if let fieldName, let error = validation?.error(for: fieldName) { - Text(error).font(.caption).foregroundStyle(.red) + Label(error, systemImage: "exclamationmark.circle").font(.caption).foregroundStyle(.red) } else if let hint = props.string("hint"), !hint.isEmpty { Text(hint).font(.caption).foregroundStyle(.secondary) } @@ -85,7 +87,8 @@ struct InputView: View { #endif } } - .textFieldStyle(.roundedBorder) + .textFieldStyle(.plain) + .fieldSurface() .disabled(context.isStreaming) .onSubmit { if !state.rules.isEmpty { @@ -131,7 +134,8 @@ struct TextAreaView: View { axis: .vertical ) .lineLimit(rows...max(rows, 12)) - .textFieldStyle(.roundedBorder) + .textFieldStyle(.plain) + .fieldSurface() .disabled(context.isStreaming) .formField(state.field.name, rules: state.rules, value: state.field.value) } @@ -141,6 +145,7 @@ struct TextAreaView: View { struct SelectView: View { let props: ComponentProps + @Environment(\.openUITheme) private var theme @Environment(OpenUIContext.self) private var context @Environment(\.openUIFormName) private var form @Environment(FormValidation.self) private var validation: FormValidation? @@ -148,25 +153,40 @@ struct SelectView: View { var body: some View { let state = FieldContext(props, context: context, form: form) let items = props.children("items") - Picker( - props.text("placeholder"), - selection: Binding( - get: { displayText(state.field.value) }, - set: { newValue in - state.field.setValue(.string(newValue)) - if !state.rules.isEmpty { - validation?.validateField( - state.field.name, value: .string(newValue), rules: state.rules) - } - }) - ) { - Text(props.string("placeholder") ?? "Select…").tag("") - ForEach(Array(items.enumerated()), id: \.offset) { _, item in - Text(item.text("label")).tag(item.text("value")) + let current = displayText(state.field.value) + let label = items.first { $0.text("value") == current }?.text("label") + // A full-width field like react-ui's select, opening a native menu. + Menu { + Picker( + props.text("placeholder"), + selection: Binding( + get: { current }, + set: { newValue in + state.field.setValue(.string(newValue)) + if !state.rules.isEmpty { + validation?.validateField( + state.field.name, value: .string(newValue), rules: state.rules) + } + }) + ) { + ForEach(items.indices, id: \.self) { index in + Text(items[index].text("label")).tag(items[index].text("value")) + } + } + .pickerStyle(.inline) + } label: { + HStack { + Text(label ?? props.string("placeholder") ?? "Select…") + .foregroundStyle(label == nil ? .secondary : .primary) + Spacer() + Image(systemName: "chevron.down").font(.caption).foregroundStyle(.secondary) } + .frame(maxWidth: .infinity) + .fieldSurface(border: theme.border) + .contentShape(Rectangle()) } - .pickerStyle(.menu) - .labelsHidden() + .menuIndicator(.hidden) + .buttonStyle(.plain) .disabled(context.isStreaming) .formField(state.field.name, rules: state.rules, value: state.field.value) } @@ -261,15 +281,19 @@ private struct BooleanGroup: View { } .buttonStyle(.plain) case .toggle: - Toggle(isOn: Binding(get: { isOn }, set: { _ in toggle() })) { + // The switch leads and the text follows, as in react-ui's SwitchItem. + HStack(alignment: .top, spacing: 8) { + Toggle(item.text("label"), isOn: Binding(get: { isOn }, set: { _ in toggle() })) + .toggleStyle(.switch) + .labelsHidden() VStack(alignment: .leading, spacing: 2) { Text(item.text("label")) if let description = item.string("description"), !description.isEmpty { Text(description).font(.caption).foregroundStyle(.secondary) } } + .frame(maxWidth: .infinity, alignment: .leading) } - .toggleStyle(.switch) } } } @@ -342,13 +366,32 @@ private let dayFormatter: DateFormatter = { struct DatePickerView: View { let props: ComponentProps + @Environment(\.openUITheme) private var theme @Environment(OpenUIContext.self) private var context @Environment(\.openUIFormName) private var form @Environment(FormValidation.self) private var validation: FormValidation? var body: some View { let state = FieldContext(props, context: context, form: form) - if props.string("mode") == "range" { + let isRange = props.string("mode") == "range" + if state.field.value.isNullish { + // Nothing is picked until the user picks it, so the form can't submit a + // date the user never chose. + Button { + let today = OpenUIValue.string(dayFormatter.string(from: Date())) + set(state, isRange ? .object(["from": today, "to": today]) : today) + } label: { + HStack { + Text(isRange ? "Select a range" : "Select a date").foregroundStyle(.secondary) + Spacer() + Image(systemName: "calendar").foregroundStyle(.secondary) + } + .fieldSurface(border: theme.border) + } + .buttonStyle(.plain) + .disabled(context.isStreaming) + .formField(state.field.name, rules: state.rules, value: state.field.value) + } else if isRange { VStack(alignment: .leading, spacing: 6) { rangePicker("From", key: "from", state) rangePicker("To", key: "to", state) @@ -431,6 +474,13 @@ struct SliderView: View { Slider(value: binding, in: minimum...maximum) } } + HStack { + Text(compactNumber(minimum)) + Spacer() + Text(compactNumber(maximum)) + } + .font(.caption.monospacedDigit()) + .foregroundStyle(.secondary) } .disabled(context.isStreaming) .formField(state.field.name, rules: state.rules, value: state.field.value) @@ -441,6 +491,7 @@ struct SliderView: View { struct ButtonView: View { let props: ComponentProps + @Environment(\.openUIButtonFillsWidth) private var fillsWidth @Environment(OpenUIContext.self) private var context @Environment(\.openUIFormName) private var form @Environment(FormValidation.self) private var validation: FormValidation? @@ -456,7 +507,7 @@ struct ButtonView: View { } context.triggerAction(label, form: form, action: action.isNullish ? nil : action) } label: { - Text(label) + Text(label).frame(maxWidth: fillsWidth ? .infinity : nil) } .modifier(ButtonVariant(variant: variant)) .controlSize(controlSize) @@ -486,6 +537,18 @@ struct ButtonView: View { } } +private struct ButtonFillsWidthKey: EnvironmentKey { + static let defaultValue = false +} + +extension EnvironmentValues { + /// Whether buttons stretch to the available width, like a card footer's. + var openUIButtonFillsWidth: Bool { + get { self[ButtonFillsWidthKey.self] } + set { self[ButtonFillsWidthKey.self] = newValue } + } +} + private struct ButtonVariant: ViewModifier { let variant: String @@ -515,3 +578,33 @@ struct ButtonsView: View { } } } + +/// react-ui's slider labels: 1000 and up in short compact notation ("10k", +/// "2.5m"), smaller numbers as JavaScript prints them. +func compactNumber(_ number: Double) -> String { + guard number >= 1000 else { return jsNumberToString(number) } + return number.formatted( + .number.notation(.compactName).locale(Locale(identifier: "en_US")) + ).lowercased() +} + +/// react-ui's field look: a faint fill, a 1pt border and 10pt corners. +private struct FieldSurface: ViewModifier { + var border: Color? + @Environment(\.openUITheme) private var theme + + func body(content: Content) -> some View { + content + .padding(.horizontal, 10) + .padding(.vertical, 8) + .background(theme.subtleSurface, in: RoundedRectangle(cornerRadius: 10)) + .overlay( + RoundedRectangle(cornerRadius: 10).strokeBorder(border ?? theme.interactiveBorder)) + } +} + +extension View { + fileprivate func fieldSurface(border: Color? = nil) -> some View { + modifier(FieldSurface(border: border)) + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift index 86da4fd1be..9b283bddc0 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift @@ -411,11 +411,12 @@ struct TagLabel: View { } .font(font) .foregroundStyle(onImage ? Color.white : neutral ? Color.primary : color) - .padding(.horizontal, 8) - .padding(.vertical, 3) + .padding(tagPadding(size)) // On a photo the variant tint isn't readable, so react-ui switches every // tag to white on translucent black there. - .background(onImage ? Color.black.opacity(0.4) : color.opacity(0.12), in: Capsule()) + .background( + onImage ? Color.black.opacity(0.4) : color.opacity(0.12), + in: RoundedRectangle(cornerRadius: tagRadius(size))) } private var font: Font { @@ -438,3 +439,15 @@ extension EnvironmentValues { set { self[TagOnImageKey.self] = newValue } } } + +/// react-ui's tag padding per size: 4/6, 6/8 and 8/12. +func tagPadding(_ size: String?) -> EdgeInsets { + switch size { + case "sm": return EdgeInsets(top: 4, leading: 6, bottom: 4, trailing: 6) + case "lg": return EdgeInsets(top: 8, leading: 12, bottom: 8, trailing: 12) + default: return EdgeInsets(top: 6, leading: 8, bottom: 6, trailing: 8) + } +} + +/// react-ui's tag corner radius: 6, or 8 for large tags. +func tagRadius(_ size: String?) -> CGFloat { size == "lg" ? 8 : 6 } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift index db30dc2ebc..bf77702630 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift @@ -8,6 +8,7 @@ import SwiftUI struct TableView: View { let props: ComponentProps @State private var page = 0 + @Environment(OpenUIContext.self) private var context @Environment(\.openUITheme) private var theme private static let pageSize = 10 @@ -26,53 +27,82 @@ struct TableView: View { stride(from: current * Self.pageSize, to: min(rowCount, (current + 1) * Self.pageSize), by: 1) ) - VStack(alignment: .leading, spacing: theme.compactSpacing) { - ScrollView(.horizontal, showsIndicators: false) { - Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 8) { - GridRow { - ForEach(Array(columns.enumerated()), id: \.offset) { index, column in - Text(column.text("label")) - .font(.subheadline.weight(.semibold)) - .gridColumnAlignment(isNumeric(column) ? .trailing : .leading) - } + if context.isQueryLoading && rowCount == 0 { + // Placeholder rows while a Query fills the table, like react-ui's skeleton. + VStack(alignment: .leading, spacing: 10) { + ForEach(0..<5, id: \.self) { _ in + RoundedRectangle(cornerRadius: 4).fill(theme.sunkSurface).frame(height: 14) + } + } + } else if !columns.isEmpty { + VStack(alignment: .leading, spacing: theme.compactSpacing) { + // Full width like react-ui's table; scrolls sideways when the columns + // don't fit. + ViewThatFits(in: .horizontal) { + grid(columns, data, rows) + ScrollView(.horizontal, showsIndicators: false) { + grid(columns, data, rows).fixedSize(horizontal: true, vertical: false) } - Divider() - ForEach(rows, id: \.self) { row in - GridRow { - ForEach(Array(columns.enumerated()), id: \.offset) { index, column in - cell(row < data[index].count ? data[index][row] : .null, numeric: isNumeric(column)) - } + } + .clipShape(RoundedRectangle(cornerRadius: 14)) + .overlay(RoundedRectangle(cornerRadius: 14).strokeBorder(theme.border)) + if pages > 1 { + HStack(spacing: 8) { + Spacer() + Button("Previous page", systemImage: "chevron.left") { page = max(0, current - 1) } + .disabled(current == 0) + Text("\(current + 1) / \(pages)").font(.caption.monospacedDigit()) + .foregroundStyle(.secondary) + Button("Next page", systemImage: "chevron.right") { + page = min(pages - 1, current + 1) } - if row != rows.last { Divider().opacity(0.5) } + .disabled(current >= pages - 1) } + .labelStyle(.iconOnly) + .buttonStyle(.bordered) + .controlSize(.small) } - .padding(.vertical, 4) } - if pages > 1 { - HStack { - Button("Previous") { page = max(0, current - 1) }.disabled(current == 0) - Spacer() - Text("\(current + 1) / \(pages)").font(.caption.monospacedDigit()).foregroundStyle( - .secondary) - Spacer() - Button("Next") { page = min(pages - 1, current + 1) }.disabled(current >= pages - 1) + } + } + + private func grid(_ columns: [ComponentProps], _ data: [[OpenUIValue]], _ rows: [Int]) + -> some View + { + Grid(alignment: .leading, horizontalSpacing: 0, verticalSpacing: 0) { + GridRow { + ForEach(columns.indices, id: \.self) { index in + Text(columns[index].text("label")) + .font(.subheadline) + .foregroundStyle(.secondary) + .padding(12) + .frame(maxWidth: .infinity, alignment: .leading) } - .buttonStyle(.borderless) - .font(.caption) + } + theme.border.frame(height: 1) + ForEach(rows.indices, id: \.self) { position in + let row = rows[position] + GridRow { + ForEach(columns.indices, id: \.self) { index in + cell(row < data[index].count ? data[index][row] : .null) + .padding(12) + .frame(maxWidth: .infinity, alignment: .leading) + // Every second row is tinted, as in react-ui. + .background(position % 2 == 1 ? theme.subtleSurface : .clear) + } + } + if position < rows.count - 1 { theme.border.frame(height: 1) } } } } - private func isNumeric(_ column: ComponentProps) -> Bool { column.string("type") == "number" } - @ViewBuilder - private func cell(_ value: OpenUIValue, numeric: Bool) -> some View { + private func cell(_ value: OpenUIValue) -> some View { switch value { case .element, .array: OpenUINode(value) default: - Text(displayText(value)) - .font(numeric ? .callout.monospacedDigit() : .callout) + Text(displayText(value)).font(.subheadline) } } } @@ -164,14 +194,24 @@ private struct ListRow: View { } } +/// "Related Queries" and a divided list of suggestions, like react-ui's +/// FollowUpBlock; tapping one sends its text as the user's message. struct FollowUpBlockView: View { let props: ComponentProps @Environment(OpenUIContext.self) private var context + @Environment(\.openUITheme) private var theme var body: some View { - VStack(alignment: .leading, spacing: 6) { - ForEach(Array(props.children("items").enumerated()), id: \.offset) { _, item in - FollowUpButton(text: item.text("text")) { context.triggerAction(item.text("text")) } + let items = props.children("items") + VStack(alignment: .leading, spacing: 0) { + Text("Related Queries") + .foregroundStyle(.secondary) + .padding(.vertical, 8) + theme.border.frame(height: 1) + ForEach(items.indices, id: \.self) { index in + let text = items[index].text("text") + FollowUpButton(text: text) { context.triggerAction(text) } + if index < items.count - 1 { theme.border.frame(height: 1) } } } .disabled(context.isStreaming) @@ -195,13 +235,13 @@ private struct FollowUpButton: View { var body: some View { Button(action: action) { - HStack(spacing: 6) { - Image(systemName: "arrow.turn.down.right").font(.caption) - Text(text).multilineTextAlignment(.leading) - } - .font(.subheadline) + Text(text) + .multilineTextAlignment(.leading) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.vertical, 8) + .contentShape(Rectangle()) } - .buttonStyle(.borderless) + .buttonStyle(.plain) } } @@ -249,68 +289,159 @@ private struct StepContent: View { // MARK: - Tabs, accordions and sections +/// Underlined tabs. Until the user picks one, the selection follows the stream +/// to whichever tab's content grew last, like react-ui's Tabs. struct TabsView: View { let props: ComponentProps - @State private var selected: String? + @State private var active: String? + @State private var userChose = false + @State private var contentSizes: [String: Int] = [:] @Environment(\.openUITheme) private var theme var body: some View { - let items = props.children("items") - let current = selected ?? items.first?.text("value") - VStack(alignment: .leading, spacing: theme.spacing) { - Picker("", selection: Binding(get: { current ?? "" }, set: { selected = $0 })) { - ForEach(Array(items.enumerated()), id: \.offset) { _, item in - Text(item.text("trigger")).tag(item.text("value")) + let items = props.children("items").filter { !$0["value"].isNullish } + let sizes = items.map { + (value: $0.text("value"), size: JSON.stringify($0["content"]).utf16.count) + } + if !items.isEmpty { + VStack(alignment: .leading, spacing: theme.spacing) { + ScrollViewReader { proxy in + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: 20) { + ForEach(items.indices, id: \.self) { index in + tab(items[index]).id(items[index].text("value")) + } + } + } + // Keep the active tab in view as the selection follows the stream. + .onChange(of: active) { + withAnimation { proxy.scrollTo(active, anchor: .center) } + } + } + if let item = items.first(where: { $0.text("value") == active }) { + OpenUINodes(item.array("content")) } } - .pickerStyle(.segmented) - .labelsHidden() - if let item = items.first(where: { $0.text("value") == current }) { - OpenUINodes(item.array("content")) - } + .onChange(of: sizes.map(\.size), initial: true) { followStream(sizes) } } } + + private func tab(_ item: ComponentProps) -> some View { + let value = item.text("value") + let isActive = value == active + return Button { + userChose = true + active = value + } label: { + Text(item.text("trigger")) + .font(.subheadline.weight(isActive ? .semibold : .regular)) + .foregroundStyle(isActive ? .primary : .secondary) + .padding(.vertical, 6) + .overlay(alignment: .bottom) { + if isActive { Rectangle().fill(.primary).frame(height: 2) } + } + } + .buttonStyle(.plain) + } + + private func followStream(_ sizes: [(value: String, size: Int)]) { + if active == nil { active = sizes.first?.value } + guard !userChose else { return } + var candidate: String? + for (value, size) in sizes where size > (contentSizes[value] ?? 0) { candidate = value } + contentSizes = Dictionary(sizes.map { ($0.value, $0.size) }, uniquingKeysWith: { $1 }) + if let candidate { active = candidate } + } } +/// One item open at a time. Until the user opens or closes one, the newest +/// item opens as it streams in, like react-ui's Accordion. struct AccordionView: View { let props: ComponentProps + @State private var open: String? + @State private var userChose = false + @State private var seenCount = 0 var body: some View { + let items = props.children("items") VStack(alignment: .leading, spacing: 0) { - let items = props.children("items") - ForEach(Array(items.enumerated()), id: \.offset) { index, item in + ForEach(items.indices, id: \.self) { index in + let value = items[index].text("value") Disclosure( - trigger: item.text("trigger"), content: item.array("content"), initiallyOpen: false) + trigger: items[index].text("trigger"), content: items[index].array("content"), + isOpen: Binding( + get: { open == value }, + set: { isOpen in + userChose = true + open = isOpen ? value : nil + })) if index < items.count - 1 { Divider() } } } + .onChange(of: items.count, initial: true) { + if !userChose, items.count > seenCount, let newest = items.last { + open = newest.text("value") + } + seenCount = items.count + } } } +/// Sections open as they stream in, then fold back to the first one when the +/// response finishes (unless the user opened or closed one), like react-ui's +/// SectionBlock. With `isFoldable: false` every section is shown. struct SectionBlockView: View { let props: ComponentProps + @State private var open: Set = [] + @State private var userChose = false + @State private var seenCount = 0 + @Environment(OpenUIContext.self) private var context @Environment(\.openUITheme) private var theme var body: some View { let sections = props.children("sections") - let foldable = props.bool("isFoldable") ?? true - VStack(alignment: .leading, spacing: foldable ? 0 : theme.spacing) { - ForEach(Array(sections.enumerated()), id: \.offset) { index, section in - if foldable { - // Sections open by default so they reveal content as it streams in. - Disclosure( - trigger: section.text("trigger"), content: section.array("content"), initiallyOpen: true - ) - if index < sections.count - 1 { Divider() } - } else { + let values = sections.indices.map { sectionValue(sections[$0], $0) } + if props.bool("isFoldable") == false { + VStack(alignment: .leading, spacing: theme.spacing) { + ForEach(sections.indices, id: \.self) { index in VStack(alignment: .leading, spacing: theme.compactSpacing) { - Text(section.text("trigger")).font(.headline) - OpenUINodes(section.array("content")) + Text(sections[index].text("trigger")).font(.headline) + OpenUINodes(sections[index].array("content")) } } } + } else { + VStack(alignment: .leading, spacing: 0) { + ForEach(sections.indices, id: \.self) { index in + let value = values[index] + Disclosure( + trigger: sections[index].text("trigger"), content: sections[index].array("content"), + isOpen: Binding( + get: { open.contains(value) }, + set: { isOpen in + userChose = true + if isOpen { open.insert(value) } else { open.remove(value) } + })) + if index < sections.count - 1 { Divider() } + } + } + .onChange(of: values.count, initial: true) { + if context.isStreaming, values.count > seenCount, !userChose, let last = values.last { + open.insert(last) + } else if open.isEmpty, let first = values.first { + open = [first] + } + seenCount = values.count + } + .onChange(of: context.isStreaming) { wasStreaming, isStreaming in + if wasStreaming, !isStreaming, !userChose, let first = values.first { open = [first] } + } } } + + private func sectionValue(_ section: ComponentProps, _ index: Int) -> String { + section["value"].isNullish ? String(index) : section.text("value") + } } /// A sub-item rendered on its own: its trigger as a heading, then its content. @@ -329,13 +460,7 @@ struct TriggeredContentView: View { private struct Disclosure: View { let trigger: String let content: [OpenUIValue] - @State private var isOpen: Bool - - init(trigger: String, content: [OpenUIValue], initiallyOpen: Bool) { - self.trigger = trigger - self.content = content - _isOpen = State(initialValue: initiallyOpen) - } + @Binding var isOpen: Bool var body: some View { DisclosureGroup(isExpanded: $isOpen) { diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift index bfb9a39ace..94eabc5040 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift @@ -24,10 +24,11 @@ private func storedSelection(_ values: [String], single: Bool) -> OpenUIValue { return .array(values.map(OpenUIValue.string)) } -/// Field plumbing shared by Chips and OptionCards. +/// Field plumbing shared by Chips (wrapping row) and OptionCards (card grid). private struct SelectionField: View { let props: ComponentProps let componentType: String + var grid = false @ViewBuilder let option: (ComponentProps, Bool, @escaping () -> Void) -> Option @Environment(OpenUIContext.self) private var context @Environment(\.openUIFormName) private var form @@ -39,25 +40,18 @@ private struct SelectionField: View { let rules = parseStructuredRules(props["rules"]) let selected = selection( stored: field.value, defaultValue: props["defaultValue"], single: single) - FlowLayout(spacing: 8) { - ForEach(Array(props.children("items").enumerated()), id: \.offset) { _, item in - let value = item.text("value") - option(item, selected.contains(value)) { - var next = selected - if single { - next = selected == [value] ? [] : [value] - } else if let index = next.firstIndex(of: value) { - next.remove(at: index) - } else { - next.append(value) - } - let stored = storedSelection(next, single: single) - field.setValue(stored) - if !rules.isEmpty { - validation?.validateField(field.name, value: stored, rules: rules) + let items = props.children("items") + Group { + if grid { + ResponsiveCardGrid(count: items.count, maxPerRow: 3) { index in + optionView(items[index], selected: selected, single: single, field: field, rules: rules) + } + } else { + FlowLayout(spacing: 8) { + ForEach(items.indices, id: \.self) { index in + optionView(items[index], selected: selected, single: single, field: field, rules: rules) } } - .disabled(item.bool("disabled") == true) } } .disabled(context.isStreaming) @@ -66,6 +60,29 @@ private struct SelectionField: View { .onChange(of: context.isStreaming) { seedDefault(single: single, field: field) } } + private func optionView( + _ item: ComponentProps, selected: [String], single: Bool, field: StateField, + rules: [ParsedRule] + ) -> some View { + let value = item.text("value") + return option(item, selected.contains(value)) { + var next = selected + if single { + next = selected == [value] ? [] : [value] + } else if let index = next.firstIndex(of: value) { + next.remove(at: index) + } else { + next.append(value) + } + let stored = storedSelection(next, single: single) + field.setValue(stored) + if !rules.isEmpty { + validation?.validateField(field.name, value: stored, rules: rules) + } + } + .disabled(item.bool("disabled") == true) + } + /// Stores the default once streaming ends, without notifying the host. private func seedDefault(single: Bool, field: StateField) { guard !field.isReactive else { return } @@ -107,11 +124,15 @@ private struct Chip: View { Text(item.text("label")) } .font(.subheadline) - .padding(.horizontal, 12) + .padding(.horizontal, 8) .padding(.vertical, 6) - .foregroundStyle(isOn ? Color.white : Color.primary) - .background(isOn ? Color.accentColor : theme.sunkSurface, in: Capsule()) - .overlay(Capsule().strokeBorder(isOn ? Color.clear : theme.border)) + .background( + isOn ? Color.primary.opacity(0.08) : .clear, in: RoundedRectangle(cornerRadius: 8) + ) + .overlay( + RoundedRectangle(cornerRadius: 8).strokeBorder(isOn ? .primary : theme.interactiveBorder) + ) + .contentShape(RoundedRectangle(cornerRadius: 8)) } .buttonStyle(.plain) .accessibilityAddTraits(isOn ? .isSelected : []) @@ -123,7 +144,7 @@ private struct Chip: View { struct OptionCardsView: View { let props: ComponentProps var body: some View { - SelectionField(props: props, componentType: "OptionCards") { item, isOn, toggle in + SelectionField(props: props, componentType: "OptionCards", grid: true) { item, isOn, toggle in OptionCardTile(item: item, isOn: isOn, action: toggle) } } @@ -145,8 +166,10 @@ private struct OptionCardTile: View { VStack(alignment: .leading, spacing: 6) { switch item["topContent"] { case .element(let element) where element.typeName == "Icon": - Image(systemName: iconSymbol(item["topContent"]) ?? "circle").font(.title2) - .foregroundStyle(Color.accentColor) + Image(systemName: iconSymbol(item["topContent"]) ?? "circle") + .font(.system(size: 14)) + .frame(width: 32, height: 32) + .background(theme.sunkSurface, in: RoundedRectangle(cornerRadius: 8)) case .element: OpenUINode(item["topContent"]).frame(height: 90).clipped() default: @@ -157,12 +180,13 @@ private struct OptionCardTile: View { Text(subtitle).font(.caption).foregroundStyle(.secondary) } } - .padding(12) - .frame(width: 160, alignment: .topLeading) - .background(theme.surface, in: RoundedRectangle(cornerRadius: theme.cornerRadius)) + .padding(10) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + .background(isOn ? theme.sunkSurface : .clear, in: RoundedRectangle(cornerRadius: 14)) .overlay( - RoundedRectangle(cornerRadius: theme.cornerRadius) - .strokeBorder(isOn ? Color.accentColor : theme.border, lineWidth: isOn ? 2 : 1)) + RoundedRectangle(cornerRadius: 14).strokeBorder(isOn ? .primary : theme.interactiveBorder) + ) + .contentShape(RoundedRectangle(cornerRadius: 14)) } .buttonStyle(.plain) .accessibilityAddTraits(isOn ? .isSelected : []) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift index 2a6e6760c6..a0ed71355a 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift @@ -1,3 +1,4 @@ +import OpenUILang import SwiftUI /// Text with inline markdown (bold, italic, code, links), falling back to the @@ -16,27 +17,128 @@ struct InlineMarkdown: View { static func attributed(_ source: String) -> AttributedString { let options = AttributedString.MarkdownParsingOptions( interpretedSyntax: .inlineOnlyPreservingWhitespace) - return (try? AttributedString(markdown: source, options: options)) ?? AttributedString(source) + // Only ~~double~~ tildes strike through, as in react-ui; a lone "~$5K" + // ("about") stays literal. + return (try? AttributedString(markdown: escapingLoneTildes(source), options: options)) + ?? AttributedString(source) + } + + private static func escapingLoneTildes(_ source: String) -> String { + let characters = Array(source) + var result = "" + for (index, character) in characters.enumerated() { + if character == "~", characters[safe: index - 1] != "~", characters[safe: index + 1] != "~" { + result += "\\~" + } else { + result.append(character) + } + } + return result + } +} + +/// Inline markdown with react-ui's citations: a run of `[1][2]` markers +/// becomes a small globe when the card has a source with a title and name for +/// one of them, and disappears otherwise. +struct CitedMarkdown: View { + let source: String + @Environment(\.openUICardSources) private var sources + + var body: some View { + let segments = Self.segments(source) + return segments.indices.reduce(Text("")) { text, index in + switch segments[index] { + case .text(let part): + return text + Text(InlineMarkdown.attributed(part)) + case .citation(let indices) where hasSource(indices): + // The marker pattern swallows the space after it; put it back before a word. + let spaced: Bool = { + guard index + 1 < segments.count, case .text(let next) = segments[index + 1] else { + return false + } + return next.first.map { $0.isLetter || $0.isNumber } ?? false + }() + return text + Text(Image(systemName: "globe")).font(.caption).foregroundStyle(.secondary) + + Text(spaced ? " " : "") + case .citation: + return text + } + } + } + + enum Segment: Equatable { + case text(String) + case citation([Int]) + } + + /// Splits on react-ui's citation pattern, `(\[\d+\]\s*)+`. + nonisolated static func segments(_ source: String) -> [Segment] { + let pattern = /(\[\d+\]\s*)+/ + var segments: [Segment] = [] + var rest = source[...] + while let match = rest.firstMatch(of: pattern) { + if match.range.lowerBound > rest.startIndex { + segments.append(.text(String(rest[.. Bool { + indices.contains { index in + guard index >= 1, index <= sources.count else { return false } + let source = sources[index - 1] + let title = source["title"].stringValue?.trimmingCharacters(in: .whitespaces) ?? "" + let name = source["sourceName"].stringValue?.trimmingCharacters(in: .whitespaces) ?? "" + return !title.isEmpty && !name.isEmpty + } + } +} + +private struct CardSourcesKey: EnvironmentKey { + static let defaultValue: [OpenUIValue] = [] +} + +extension EnvironmentValues { + /// The enclosing Card's `sources`, which inline citations refer to. + var openUICardSources: [OpenUIValue] { + get { self[CardSourcesKey.self] } + set { self[CardSourcesKey.self] = newValue } } } /// Block-level markdown: headings, bullet and numbered lists, quotes, code /// fences, rules and paragraphs. Inline formatting uses `InlineMarkdown`. struct MarkdownBlocks: View { - enum Block { + enum Block: Equatable { case heading(level: Int, text: String) case bullet(String) case numbered(String, String) case quote(String) case code(String) + /// `$$ … $$` math. There's no native TeX renderer, so it shows as source. + case math(String) + case table(header: [String], rows: [[String]]) case rule case paragraph(String) } let blocks: [Block] + /// Renders `[n]` markers as citations (TextContent does, MarkDownRenderer doesn't). + let citations: Bool - init(_ source: String) { + init(_ source: String, citations: Bool = false) { blocks = Self.parse(source) + self.citations = citations + } + + @ViewBuilder + private func inline(_ text: String) -> some View { + if citations { CitedMarkdown(source: text) } else { InlineMarkdown(text) } } var body: some View { @@ -51,29 +153,49 @@ struct MarkdownBlocks: View { private func view(for block: Block) -> some View { switch block { case .heading(let level, let text): - InlineMarkdown(text).font( + inline(text).font( level <= 1 ? .title2.bold() : level == 2 ? .title3.bold() : .headline) case .bullet(let text): HStack(alignment: .firstTextBaseline, spacing: 6) { Text("•") - InlineMarkdown(text) + inline(text) } case .numbered(let marker, let text): HStack(alignment: .firstTextBaseline, spacing: 6) { Text(marker).monospacedDigit() - InlineMarkdown(text) + inline(text) } case .quote(let text): - InlineMarkdown(text) + inline(text) .foregroundStyle(.secondary) .padding(.leading, 10) .overlay(alignment: .leading) { Rectangle().fill(.secondary.opacity(0.4)).frame(width: 3) } case .code(let text): Text(text).font(.system(.callout, design: .monospaced)) + case .math(let tex): + Text(tex) + .font(.system(.callout, design: .monospaced)) + .padding(8) + .frame(maxWidth: .infinity, alignment: .leading) + .background(Color.primary.opacity(0.04), in: RoundedRectangle(cornerRadius: 8)) + case .table(let header, let rows): + ScrollView(.horizontal, showsIndicators: false) { + Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 6) { + GridRow { + ForEach(header.indices, id: \.self) { inline(header[$0]).fontWeight(.semibold) } + } + Divider() + ForEach(rows.indices, id: \.self) { row in + GridRow { + ForEach(rows[row].indices, id: \.self) { inline(rows[row][$0]) } + } + } + } + } case .rule: Divider() case .paragraph(let text): - InlineMarkdown(text) + inline(text) } } @@ -81,6 +203,29 @@ struct MarkdownBlocks: View { var blocks: [Block] = [] var paragraph: [String] = [] var code: [String]? = nil + var math: [String]? = nil + var table: [[String]] = [] + + func cells(_ line: String) -> [String] { + var trimmed = Substring(line) + if trimmed.hasPrefix("|") { trimmed = trimmed.dropFirst() } + if trimmed.hasSuffix("|") { trimmed = trimmed.dropLast() } + return trimmed.split(separator: "|", omittingEmptySubsequences: false).map { + $0.trimmingCharacters(in: .whitespaces) + } + } + + func flushTable() { + // A GFM table: header, a ---|--- separator, then rows. + if table.count >= 2, + table[1].allSatisfy({ !$0.isEmpty && $0.allSatisfy { "-: ".contains($0) } }) + { + blocks.append(.table(header: table[0], rows: Array(table.dropFirst(2)))) + } else { + paragraph.append(contentsOf: table.map { "| " + $0.joined(separator: " | ") + " |" }) + } + table = [] + } func flushParagraph() { if !paragraph.isEmpty { @@ -91,6 +236,33 @@ struct MarkdownBlocks: View { for rawLine in source.components(separatedBy: "\n") { let line = rawLine.trimmingCharacters(in: .whitespaces) + if math != nil { + if line.hasSuffix("$$") { + math!.append(String(line.dropLast(2))) + blocks.append( + .math(math!.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines))) + math = nil + } else { + math!.append(rawLine) + } + continue + } + if !table.isEmpty, !line.hasPrefix("|") { flushTable() } + if line.hasPrefix("$$"), code == nil { + flushParagraph() + let rest = line.dropFirst(2) + if rest.hasSuffix("$$"), rest.count >= 2 { + blocks.append(.math(String(rest.dropLast(2)).trimmingCharacters(in: .whitespaces))) + } else { + math = [String(rest)] + } + continue + } + if line.hasPrefix("|"), code == nil { + if table.isEmpty { flushParagraph() } + table.append(cells(line)) + continue + } if line.hasPrefix("```") { if let lines = code { blocks.append(.code(lines.joined(separator: "\n"))) @@ -132,6 +304,8 @@ struct MarkdownBlocks: View { paragraph.append(line) } } + if !table.isEmpty { flushTable() } + if let lines = math { blocks.append(.math(lines.joined(separator: "\n"))) } if let lines = code { blocks.append(.code(lines.joined(separator: "\n"))) } flushParagraph() return blocks diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift index 42a09f2fd2..c5fd347bc6 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift @@ -2,16 +2,25 @@ import SwiftUI /// Spacing, shapes and colors the built-in components use. Override parts of /// it with `.environment(\.openUITheme, theme)`. +/// +/// The defaults follow react-ui's design tokens (spacing, radii, and the +/// translucent fills and borders), so both renderers look alike. public struct OpenUITheme: Sendable { public var spacing: CGFloat = 12 public var compactSpacing: CGFloat = 6 public var cornerRadius: CGFloat = 10 public var smallCornerRadius: CGFloat = 6 - public var cardPadding: CGFloat = 16 + public var cardPadding: CGFloat = 18 public var accent: Color = .accentColor - public var surface: Color = .platformSecondaryBackground - public var sunkSurface: Color = .platformTertiaryBackground - public var border: Color = .secondary.opacity(0.25) + /// Raised surfaces such as clickable cards (react-ui's `foreground`). + public var surface: Color = .platformElevatedBackground + /// Recessed fills such as inputs (react-ui's `sunk`). + public var sunkSurface: Color = .primary.opacity(0.04) + /// The faint fill of static cards (react-ui's `sunk-light`). + public var subtleSurface: Color = .primary.opacity(0.02) + public var border: Color = .primary.opacity(0.06) + /// Borders of clickable cards (react-ui's `border-interactive`). + public var interactiveBorder: Color = .primary.opacity(0.12) public var chartHeight: CGFloat = 220 public init() {} @@ -31,16 +40,14 @@ extension EnvironmentValues { } extension Color { - static var platformSecondaryBackground: Color { + /// White in light mode and a raised gray in dark mode. + static var platformElevatedBackground: Color { #if os(macOS) Color(nsColor: .controlBackgroundColor) #else - Color(uiColor: .secondarySystemBackground) + Color(uiColor: .secondarySystemGroupedBackground) #endif } - - /// A light recessed fill that works in light and dark mode on every platform. - static var platformTertiaryBackground: Color { Color.primary.opacity(0.06) } } /// Status colors shared by callouts, tags and form errors. @@ -65,11 +72,12 @@ struct SurfaceModifier: ViewModifier { content case "sunk": content.padding(theme.cardPadding) - .background(theme.sunkSurface, in: RoundedRectangle(cornerRadius: theme.cornerRadius)) + .background(theme.sunkSurface, in: RoundedRectangle(cornerRadius: 16)) + .overlay(RoundedRectangle(cornerRadius: 16).strokeBorder(theme.border)) default: - content.padding(theme.cardPadding) - .background(theme.surface, in: RoundedRectangle(cornerRadius: theme.cornerRadius)) - .overlay(RoundedRectangle(cornerRadius: theme.cornerRadius).strokeBorder(theme.border)) + // react-ui's "card" variant is a plain full-width column; the chat + // bubble around it provides the frame. + content } } } diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 27c6bc2de7..f77c82bd80 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -159,7 +159,9 @@ import Testing backing: .buffered, defer: false) window.contentView = host RunLoop.main.run(until: Date().addingTimeInterval(0.3)) - #expect(host.fittingSize.height > 200, "\(name) rendered \(host.fittingSize)") + // The smallest example (a short table) is about 195pt; empty or collapsed + // renders are far below this. + #expect(host.fittingSize.height > 120, "\(name) rendered \(host.fittingSize)") } /// The bug vishxrad hit in the Angular port: an input recreated on every @@ -251,3 +253,43 @@ let globalTestLibrary = SwiftUILibrary( #expect(globalTestLibrary.paramMap["Box"]?.map(\.name) == ["text"]) } } + +@Suite struct CitationTests { + @Test func splitsLikeRemarkCitations() { + #expect( + CitedMarkdown.segments("Big [1][2] news [3]. End") + == [.text("Big "), .citation([1, 2]), .text("news "), .citation([3]), .text(". End")]) + #expect(CitedMarkdown.segments("No citations") == [.text("No citations")]) + #expect(CitedMarkdown.segments("[1] [2]") == [.citation([1, 2])]) + } +} + +@MainActor +@Suite struct MarkdownTests { + @Test func parsesMathAndTables() { + let blocks = MarkdownBlocks.parse( + "Intro\n$$\nA = P(1 + r)^n\n$$\n| a | b |\n|---|:-:|\n| 1 | 2 |\nAfter $$x$$") + #expect( + blocks == [ + .paragraph("Intro"), .math("A = P(1 + r)^n"), + .table(header: ["a", "b"], rows: [["1", "2"]]), + .paragraph("After $$x$$"), + ]) + #expect(MarkdownBlocks.parse("$$E = mc^2$$") == [.math("E = mc^2")]) + // Without a separator row it's just text. + #expect(MarkdownBlocks.parse("| not | a table |") == [.paragraph("| not | a table |")]) + } + + @Test func onlyDoubleTildesStrikeThrough() { + let lone = InlineMarkdown.attributed("about ~$5K and ~4 days") + #expect(String(lone.characters) == "about ~$5K and ~4 days") + let double = InlineMarkdown.attributed("~~gone~~") + #expect(String(double.characters) == "gone") + } + + @Test func scatterDomainPadsLikeReactUI() { + #expect(ScatterChartView.domain([150, 190]) == 146...194) + #expect(ScatterChartView.domain([1, 5]) == 0.6...5.4) + #expect(ScatterChartView.domain([]) == 0...100) + } +} From cd4808a9be9ef0ed74e20ef5cc6fc5bc909bc900 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 02:10:41 +0530 Subject: [PATCH 11/52] refactor(swift-lang): bind optionals instead of force-unwrapping after checks --- .../Sources/OpenUILang/Materialize.swift | 3 +-- .../swift-lang/Sources/OpenUILang/Parser.swift | 4 ++-- .../Sources/OpenUILang/QueryManager.swift | 18 +++++++++--------- .../Sources/OpenUILang/Validation.swift | 10 ++++++---- .../Sources/OpenUISwiftUI/Support.swift | 13 +++++++------ 5 files changed, 25 insertions(+), 23 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUILang/Materialize.swift b/packages/swift-lang/Sources/OpenUILang/Materialize.swift index 4aee5ced38..c54fd1f751 100644 --- a/packages/swift-lang/Sources/OpenUILang/Materialize.swift +++ b/packages/swift-lang/Sources/OpenUILang/Materialize.swift @@ -21,11 +21,10 @@ private enum RefResolution { /// Shared ref handling: cycle and missing-symbol detection, and Query/Mutation /// declarations becoming `RuntimeRef`s. private func lookupRef(_ name: String, _ ctx: MaterializeContext) -> RefResolution { - if ctx.visited.contains(name) || ctx.syms[name] == nil { + guard !ctx.visited.contains(name), let target = ctx.syms[name] else { ctx.unres.append(name) return .unresolved } - let target = ctx.syms[name]! ctx.markReached(name) if case .comp(let callee, _, _) = target, isReservedCall(callee) { let refType: RuntimeRefType = callee == ReservedCall.mutation ? .mutation : .query diff --git a/packages/swift-lang/Sources/OpenUILang/Parser.swift b/packages/swift-lang/Sources/OpenUILang/Parser.swift index 48a72b9432..846e6c5de9 100644 --- a/packages/swift-lang/Sources/OpenUILang/Parser.swift +++ b/packages/swift-lang/Sources/OpenUILang/Parser.swift @@ -131,7 +131,7 @@ private func buildResult( var syms: [String: ASTNode] = [:] var unreached: [String] = [] for id in map.order { - let statement = map[id]! + guard let statement = map[id] else { continue } switch statement { case .state(_, let initial): syms[id] = initial @@ -147,7 +147,7 @@ private func buildResult( syms: syms, cat: cat, partial: wasIncomplete, currentStatementId: entryId) ctx.unreached = unreached var root: ElementNode? = nil - if case .element(var element) = materializeValue(syms[entryId]!, ctx) { + if let entry = syms[entryId], case .element(var element) = materializeValue(entry, ctx) { element.statementId = entryId root = element } diff --git a/packages/swift-lang/Sources/OpenUILang/QueryManager.swift b/packages/swift-lang/Sources/OpenUILang/QueryManager.swift index a49f6fd6e7..9c3af3383c 100644 --- a/packages/swift-lang/Sources/OpenUILang/QueryManager.swift +++ b/packages/swift-lang/Sources/OpenUILang/QueryManager.swift @@ -262,7 +262,7 @@ public final class QueryManager { if rebuildSnapshot() { notify() } if queries[statementId]?.needsRefetch == true { queries[statementId]?.needsRefetch = false - startFetch(queries[statementId]!.cacheKey, statementId) + if let key = queries[statementId]?.cacheKey { startFetch(key, statementId) } } } else if rebuildSnapshot() { notify() @@ -328,12 +328,12 @@ public final class QueryManager { } let interval = node.refreshInterval ?? 0 - if interval != queries[node.statementId]!.refreshInterval { - queries[node.statementId]!.timer?.cancel() - queries[node.statementId]!.timer = nil + if interval != queries[node.statementId]?.refreshInterval { + queries[node.statementId]?.timer?.cancel() + queries[node.statementId]?.timer = nil if interval > 0 { let statementId = node.statementId - queries[node.statementId]!.timer = Task { [weak self] in + queries[node.statementId]?.timer = Task { [weak self] in while !Task.isCancelled { try? await Task.sleep(nanoseconds: UInt64(interval * 1_000_000_000)) guard let self, !Task.isCancelled, !self.disposed, self.toolProvider != nil, @@ -345,7 +345,7 @@ public final class QueryManager { } } } - queries[node.statementId]!.refreshInterval = interval + queries[node.statementId]?.refreshInterval = interval } } if rebuildSnapshot() { notify() } @@ -404,8 +404,8 @@ public final class QueryManager { public func fireMutation( _ statementId: String, args: OpenUIObject, refreshQueryIds: [String]? = nil ) async -> Bool { - if disposed || toolProvider == nil { return false } - guard let mutation = mutations[statementId], mutation.result["status"].stringValue != "loading" + guard !disposed, let toolProvider, let mutation = mutations[statementId], + mutation.result["status"].stringValue != "loading" else { return false } let currentGeneration = generation mutations[statementId]?.result = ["status": "loading"] @@ -414,7 +414,7 @@ public final class QueryManager { var success = false do { - let data = try await toolProvider!.callTool(mutation.toolName, arguments: args) + let data = try await toolProvider.callTool(mutation.toolName, arguments: args) if disposed || currentGeneration != generation { return false } mutations[statementId]?.result = ["status": "success", "data": data] mutations[statementId]?.error = nil diff --git a/packages/swift-lang/Sources/OpenUILang/Validation.swift b/packages/swift-lang/Sources/OpenUILang/Validation.swift index cba934b114..5995ac956b 100644 --- a/packages/swift-lang/Sources/OpenUILang/Validation.swift +++ b/packages/swift-lang/Sources/OpenUILang/Validation.swift @@ -144,8 +144,10 @@ private func validationMessage(_ component: String, _ path: String, _ issue: Val + (signature.map { " — signature: \($0)" } ?? "") case .unknownComponent(let available): let list = - (available?.isEmpty == false) - ? ". Available components: \(available!.joined(separator: ", "))" : "" + available.flatMap { + $0.isEmpty ? nil : ". Available components: \($0.joined(separator: ", "))" + } + ?? "" return "Unknown component \"\(component)\" — not found in catalog or builtins\(list)" case .inlineReserved: return "\(component)() must be declared as a top-level statement, not used inline as a value" @@ -216,7 +218,7 @@ private func validateObjectValue( if !ctx.partial { for key in required { let present = object.contains(key) - if !present || object[key]!.isNullish { + if object[key]?.isNullish ?? true { if let fallback = schemaDefaultValue(props[key]) { object[key] = fallback continue @@ -230,7 +232,7 @@ private func validateObjectValue( } for key in props.keys where object.contains(key) { let sub = props[key] - var child = object[key]! + guard var child = object[key] else { continue } let childInvalid = validateSchemaValue(&child, sub, component, "\(path)/\(key)", ctx) object[key] = child if childInvalid, diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift index a0ed71355a..53157fe86e 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift @@ -236,14 +236,15 @@ struct MarkdownBlocks: View { for rawLine in source.components(separatedBy: "\n") { let line = rawLine.trimmingCharacters(in: .whitespaces) - if math != nil { + if var lines = math { if line.hasSuffix("$$") { - math!.append(String(line.dropLast(2))) - blocks.append( - .math(math!.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines))) + lines.append(String(line.dropLast(2))) + let tex = lines.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines) + blocks.append(.math(tex)) math = nil } else { - math!.append(rawLine) + lines.append(rawLine) + math = lines } continue } @@ -274,7 +275,7 @@ struct MarkdownBlocks: View { continue } if code != nil { - code!.append(rawLine) + code?.append(rawLine) continue } if line.isEmpty { From 8cc561b7d31bfac469906432ed83c71872743793 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 02:14:10 +0530 Subject: [PATCH 12/52] fix(swift-lang): report data in component slots like lang-core Ports #1287: a string, number, boolean, object or array in a slot that only accepts components is a type-mismatch and is pruned, and that aren't listed as components (zod's hoisted __schema0 shapes) don't count as components. The new lang-core cases are in the fixtures. --- .../swift-lang/Scripts/generate-fixtures.mjs | 17 +++ .../Sources/OpenUILang/Parser.swift | 3 + .../Sources/OpenUILang/Validation.swift | 34 ++++- .../OpenUILangTests/Fixtures/parser.json | 137 ++++++++++++++++++ .../OpenUILangTests/Fixtures/schemas.json | 29 ++++ .../OpenUILangTests/Fixtures/streaming.json | 2 +- 6 files changed, 220 insertions(+), 2 deletions(-) diff --git a/packages/swift-lang/Scripts/generate-fixtures.mjs b/packages/swift-lang/Scripts/generate-fixtures.mjs index 8b11e795a0..b186e8f377 100644 --- a/packages/swift-lang/Scripts/generate-fixtures.mjs +++ b/packages/swift-lang/Scripts/generate-fixtures.mjs @@ -123,9 +123,20 @@ const testLibrary = { ), }; +// Zod hoists recursive data shapes into $defs (__schema0); only the names +// under `properties` are components. +const hoistedSchema = { + properties: { Tree: {} }, + $defs: { + Tree: { properties: { node: { $ref: "#/$defs/__schema0" } }, required: ["node"] }, + __schema0: { type: "object", properties: { label: { type: "string" } } }, + }, +}; + const schemas = { chat: { schema: chatSchema, root: "Card", reactive: reactiveProps(ui.openuiChatLibrary) }, test: { schema: testSchema, root: "Card", reactive: testReactive }, + hoisted: { schema: hoistedSchema, root: "Tree", reactive: {} }, }; const libraries = { chat: ui.openuiChatLibrary, test: testLibrary }; @@ -232,6 +243,12 @@ const edgeCases = [ ), t("truncated-mid-call", 'root = Card([a, b])\na = Text("one")\nb = Button("tw'), t("truncated-mid-object", 'root = Card([Chart(["a"], [1], {unit: "k'), + t( + "data-in-component-slot", + 'root = Card([Text("hi"), { text: "a" }, "b", 3, [Text("x")], true])', + ), + t("data-in-component-slot-via-ref", 'root = Card(items)\nitems = [{ text: "a" }]'), + { name: "hoisted-data-def", schema: "hoisted", input: 'root = Tree({ label: "a" })' }, // OpenUI Cloud's wire format: a content marker, a fenced program, an end marker. { name: "cloud-envelope", diff --git a/packages/swift-lang/Sources/OpenUILang/Parser.swift b/packages/swift-lang/Sources/OpenUILang/Parser.swift index 846e6c5de9..2a0f8d7955 100644 --- a/packages/swift-lang/Sources/OpenUILang/Parser.swift +++ b/packages/swift-lang/Sources/OpenUILang/Parser.swift @@ -322,7 +322,10 @@ func preprocess(_ input: String) -> String { public func compileSchema(_ schema: OpenUIValue) -> ParamMap { var map = ParamMap() guard let defs = schema["$defs"].objectValue else { return map } + let components = schema["properties"].objectValue.map { Set($0.keys) } for (name, def) in defs { + // Skip non-component defs, e.g. zod's hoisted recursive schemas (__schema0). + if let components, !components.contains(name) { continue } let properties = def["properties"].objectValue ?? OpenUIObject() let required = (def["required"].arrayValue ?? []).compactMap(\.stringValue) map[name] = properties.keys.map { key in diff --git a/packages/swift-lang/Sources/OpenUILang/Validation.swift b/packages/swift-lang/Sources/OpenUILang/Validation.swift index 5995ac956b..e96d72e022 100644 --- a/packages/swift-lang/Sources/OpenUILang/Validation.swift +++ b/packages/swift-lang/Sources/OpenUILang/Validation.swift @@ -27,6 +27,24 @@ final class MaterializeContext { private let scalarTypeofs: Set = ["string", "number", "boolean"] +/// `{ $ref: "#/$defs/Name" }` → `"Name"`. +private func refName(_ schema: OpenUIValue) -> String? { + guard let ref = schema["$ref"].stringValue else { return nil } + return ref.split(separator: "/", omittingEmptySubsequences: false).last.map(String.init) +} + +/// The `$ref` names a slot allows: one for `$ref`, several for anyOf/oneOf. +private func slotRefNames(_ schema: OpenUIObject) -> [String?] { + let options = schema["anyOf"]?.arrayValue ?? schema["oneOf"]?.arrayValue ?? [.object(schema)] + return options.map(refName) +} + +/// True when every option of the slot is a `$ref` to a component. +private func isOnlyComponentSlot(_ schema: OpenUIObject, _ ctx: MaterializeContext) -> Bool { + let names = slotRefNames(schema) + return !names.isEmpty && names.allSatisfy { name in name.map { ctx.cat?[$0] != nil } ?? false } +} + private func isCompositeSchema(_ schema: OpenUIObject) -> Bool { schema.contains("$ref") || schema.contains("anyOf") || schema.contains("oneOf") || schema.contains("allOf") @@ -306,7 +324,21 @@ func validateSchemaValue( default: break } - if isCompositeSchema(s) { return false } + if isCompositeSchema(s) { + // Data (an object, array, string, number or boolean) in a component-only slot is invalid. + guard isOnlyComponentSlot(s, ctx) else { return false } + let actual: String + switch value { + case .array: actual = "array" + case .string: actual = "string" + case .number: actual = "number" + case .bool: actual = "boolean" + default: actual = "plain object" + } + let expected = slotRefNames(s).map { $0 ?? "" }.joined(separator: " | ") + pushValidationIssue(ctx, component, path, .typeMismatch(expected: expected, actual: actual)) + return true + } switch s["type"] { case .string("object"): return validateObjectValue(&value, s, component, path, ctx) case .string("array"): return validateArrayValue(&value, s, component, path, ctx) diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json index e8cc871ec5..b4fb7b6ac2 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json @@ -5656,6 +5656,143 @@ "mutationStatements": [] } }, + { + "name": "data-in-component-slot", + "schema": "test", + "input": "root = Card([Text(\"hi\"), { text: \"a\" }, \"b\", 3, [Text(\"x\")], true])", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [ + { + "type": "element", + "typeName": "Text", + "props": { + "text": "hi" + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [ + { + "code": "type-mismatch", + "component": "Card", + "path": "/children/1", + "message": "field \"/children/1\" expects Text | Button | Chart but got plain object", + "statementId": "root" + }, + { + "code": "type-mismatch", + "component": "Card", + "path": "/children/2", + "message": "field \"/children/2\" expects Text | Button | Chart but got string", + "statementId": "root" + }, + { + "code": "type-mismatch", + "component": "Card", + "path": "/children/3", + "message": "field \"/children/3\" expects Text | Button | Chart but got number", + "statementId": "root" + }, + { + "code": "type-mismatch", + "component": "Card", + "path": "/children/4", + "message": "field \"/children/4\" expects Text | Button | Chart but got array", + "statementId": "root" + }, + { + "code": "type-mismatch", + "component": "Card", + "path": "/children/5", + "message": "field \"/children/5\" expects Text | Button | Chart but got boolean", + "statementId": "root" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "data-in-component-slot-via-ref", + "schema": "test", + "input": "root = Card(items)\nitems = [{ text: \"a\" }]", + "expected": { + "root": { + "type": "element", + "typeName": "Card", + "props": { + "children": [] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 2, + "errors": [ + { + "code": "type-mismatch", + "component": "Card", + "path": "/children/0", + "message": "field \"/children/0\" expects Text | Button | Chart but got plain object", + "statementId": "root" + } + ] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "hoisted-data-def", + "schema": "hoisted", + "input": "root = Tree({ label: \"a\" })", + "expected": { + "root": { + "type": "element", + "typeName": "Tree", + "props": { + "node": { + "label": "a" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 1, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, { "name": "cloud-envelope", "schema": "chat", diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json index 86f0a2e322..e81a3102db 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json @@ -4393,5 +4393,34 @@ "value" ] } + }, + "hoisted": { + "schema": { + "properties": { + "Tree": {} + }, + "$defs": { + "Tree": { + "properties": { + "node": { + "$ref": "#/$defs/__schema0" + } + }, + "required": [ + "node" + ] + }, + "__schema0": { + "type": "object", + "properties": { + "label": { + "type": "string" + } + } + } + } + }, + "root": "Tree", + "reactive": {} } } diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json index 7055727074..8dc330a201 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json @@ -1 +1 @@ -[{"name":"chat-example-1","schema":"chat","input":"Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }","checkpoints":[{"at":607,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["highlights","statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1214,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1821,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","valu":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ov2","ov3","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":13,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2428,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[],"isFoldable":null},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secLandmarks","secFood","secWhen","f","actionBtns","src1","src2"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3035,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":null,"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["lm1tagIcon","lm2","lm3","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3642,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["lm3body","lm3tag","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":33,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"lm3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["foodCards","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4856,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Sh"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":45,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5463,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"P"},"partial":true,"hasDynamicProps":false,"statementId":"sp2"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sp3","tabSummer","actionBtns","src1","src2"],"orphaned":[],"statementCount":51,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6070,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Sein"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["su2","su3","actionBtns","src1","src2"],"orphaned":[],"statementCount":55,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6677,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":true,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":true,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{}},"partial":true,"hasDynamicProps":false,"statementId":"btn2"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btn3","src1","src2"],"orphaned":[],"statementCount":60,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7277,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":false,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"springList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":false,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":false,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":false,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":false,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{"type":"continue_conversation","context":"Show me the best hotels in Paris"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn2"},{"type":"element","typeName":"Button","props":{"label":"Build a Paris Itinerary","action":{"type":"continue_conversation","context":"Build a 5-day Paris itinerary for me"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn3"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[{"title":"Paris Travel Guide 2025","sourceName":"Travel and Tour World","url":"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/"},{"title":"Best Things to Do in Paris 2026","sourceName":"Time Out Paris","url":"http://www.timeout.fr/paris/en/for-tourists"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-2","schema":"chat","input":"Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")","checkpoints":[{"at":510,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpi1icon","kpi1rhs","kpi2","kpi3","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi1lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1020,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3icon","kpi3rhs","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":13,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi3lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1530,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabGrowth","t","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2040,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["retentio","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2550,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":35,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3060,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tab","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3570,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Sta"]},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":47,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4080,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":null,"body":[]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["supportIcon","supportMetric","supportChart","supportList","cardMarketing","actionButtons"],"orphaned":[],"statementCount":51,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"supportHeader"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4590,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","rig":null}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sup2","sup3","cardMarketing","actionButtons"],"orphaned":[],"statementCount":58,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["marketingMetric","marketingChart","marketingList","actionButtons"],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":true,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":true,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":true,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":true,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Co"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["mkt3","actionButtons"],"orphaned":[],"statementCount":70,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6118,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":false,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":false,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":false,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":false,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Cost per Lead","right":"$48.20","rightVariant":"number"},{"left":"Top Channel","right":"Organic Search","rightVariant":"text"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Break Down by Channel","action":{"type":"continue_conversation","context":"Break down this month's revenue by acquisition channel"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnChannels"},{"type":"element","typeName":"Button","props":{"label":"Forecast Next Quarter","action":{"type":"continue_conversation","context":"Forecast revenue and active users for next quarter"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnForecast"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionButtons"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":74,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-3","schema":"chat","input":"Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)","checkpoints":[{"at":361,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas"},"partial":true,"hasDynamicProps":false,"statementId":"header"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","inspoCards","form"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":722,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["i","insp2","form"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"insp1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1083,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2","form"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1444,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":null,"size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2icon","form"],"orphaned":[],"statementCount":11,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1805,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btnSkip","fcDestination","fcDates","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":15,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2166,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Fo","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":19,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2527,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tr1","tr2","tr3","tr4","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2888,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["oc2","oc3","oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":29,"errors":[{"code":"missing-required","component":"OptionCard","path":"/title","message":"missing required field \"/title\" — signature: OptionCard(value*: string, title*: string, subtitle: string, topContent, disabled: boolean)","statementId":"oc1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":34,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fcNotes"],"orphaned":[],"statementCount":39,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"fcStay"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3971,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":null},"partial":true,"hasDynamicProps":false,"statementId":"ch3"}],"rules":{},"defaultValue":["hotel"]},"partial":true,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":true,"hasDynamicProps":false,"statementId":"fcStay"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ch4","fcNotes"],"orphaned":[],"statementCount":46,"errors":[{"code":"missing-required","component":"Icon","path":"/name","message":"missing required field \"/name\" — signature: Icon(name*: string, category: string)","statementId":"ch3icon"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4322,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":false,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":false,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":{"type":"element","typeName":"Icon","props":{"name":"home","category":"home"},"partial":false,"hasDynamicProps":false,"statementId":"ch3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch3"},{"type":"element","typeName":"ChipItem","props":{"value":"camping","label":"Camping / Glamping","icon":{"type":"element","typeName":"Icon","props":{"name":"tent","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"ch4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch4"}],"rules":{},"defaultValue":["hotel"]},"partial":false,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fcStay"},{"type":"element","typeName":"FormControl","props":{"label":"Special Requests or Notes","input":{"type":"element","typeName":"TextArea","props":{"name":"special-requests","placeholder":"e.g. vegetarian meals, wheelchair access, honeymoon surprise...","rows":4},"partial":false,"hasDynamicProps":false,"statementId":"notesArea"},"hint":"Any dietary needs, accessibility requirements, or specific interests?"},"partial":false,"hasDynamicProps":false,"statementId":"fcNotes"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":50,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-4","schema":"chat","input":"Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }","checkpoints":[{"at":218,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Ene"},"partial":true,"hasDynamicProps":false,"statementId":"header"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":436,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to w"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":654,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["v1body","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"v1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":872,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":null,"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v1icon","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1090,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":null,"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v2tag","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1308,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["CompositeCard","src1","src2"],"orphaned":[],"statementCount":14,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1526,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1icon","t1body","t1tags","t1btn","t2","src1","src2"],"orphaned":[],"statementCount":16,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t1h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1744,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Wa"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2","src1","src2"],"orphaned":[],"statementCount":20,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1962,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2icon","t2body","t2tags","t2btn","src1","src2"],"orphaned":[],"statementCount":22,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t2h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":[]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2btn","src1","src2"],"orphaned":[],"statementCount":25,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2398,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceN":null}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2615,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":false,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":false,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},{"title":"Sajan Re (Official Music Video)","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=COUSCnFazzc"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-5","schema":"chat","input":"Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")","checkpoints":[{"at":37,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":74,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["title","tbl","followUps"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":111,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":""},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tbl","followUps"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":148,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":185,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs","users","followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":222,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Pyth"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years","followUps"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":259,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["years","followUps"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":296,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":333,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu1"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":370,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me m"},"partial":true,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu2"],"orphaned":[],"statementCount":8,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":407,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["FollowUpItem"],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":442,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"},{"type":"element","typeName":"FollowUpItem","props":{"text":"Show me a JavaScript comparison"},"partial":false,"hasDynamicProps":false,"statementId":"fu2"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"basic","schema":"test","input":"root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Bu"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Button","path":"/label","message":"missing required field \"/label\" — signature: Button(label*: string, action, variant: \"primary\"|\"secondary\")","statementId":"b1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-required","schema":"test","input":"root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["B"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Button"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":51,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"null-required-with-default","schema":"test","input":"root = Card([t1])\nt1 = Text(null)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"required-default-fills","schema":"test","input":"root = Card([x])\nx = Tagged(1, true, \"x\", null)","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tag"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":null,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-component","schema":"test","input":"root = Card([Mystery(\"a\"), Text(\"b\")])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mys"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mystery"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"excess-args","schema":"test","input":"root = Card([Text(\"a\", \"m\", \"extra\", 4)])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":41,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"type-mismatch-scalar","schema":"test","input":"root = Card([Text(42)], 7)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/title","message":"field \"/title\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-mismatch","schema":"test","input":"root = Card([Text(\"a\", \"xl\"), Button(\"b\", null, \"tertiary\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Button"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"terti"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"tertiary"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/size","message":"field \"/size\" expects one of [\"s\", \"m\", \"l\"] but got \"xl\"","statementId":"root"},{"code":"type-mismatch","component":"Button","path":"/variant","message":"field \"/variant\" expects one of [\"primary\", \"secondary\"] but got \"tertiary\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-partial-deferred","schema":"test","input":"root = Card([Text(\"a\", \"x","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"integer-boolean-const","schema":"test","input":"root = Card([x])\nx = Tagged(1.5, \"yes\", \"y\", \"loud\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tagg"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":{"k":"Member","obj":{"k":"Num","v":1},"field":"?"},"tone":"neutral"},"partial":true,"hasDynamicProps":true,"statementId":"x"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"loud"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"loud"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"},{"code":"type-mismatch","component":"Tagged","path":"/kind","message":"field \"/kind\" expects one of [\"x\"] but got \"y\"","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"nested-object","schema":"test","input":"root = Card([c1, c2, c3])\nc1 = Chart([\"a\"], [1], {unit: \"kg\"})\nc2 = Chart([\"a\"], [1], {scale: 2})\nc3 = Chart([\"a\"], [1], {unit: 5, scale: \"big\"})","checkpoints":[{"at":13,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c1","c2","c3"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"un":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":65,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":78,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":91,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scal":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c2"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":104,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":117,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":130,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":143,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":145,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c3"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"},{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"array-items-pruned","schema":"test","input":"root = Card([Chart([\"a\", 2, \"c\"], [1, \"x\", 3])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"element-in-data-slot","schema":"test","input":"root = Card([Chart([Text(\"a\")], [1])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unresolved-and-orphaned","schema":"test","input":"root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a","miss"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":58,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cycle","schema":"test","input":"root = Card([a])\na = Card([b])\nb = Card([a])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"b"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"self-reference","schema":"test","input":"root = Card([root])","checkpoints":[{"at":2,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["r"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["roo"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"no-root-first-component","schema":"test","input":"x = 1\nmain = Card([Text(\"a\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["main"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"main"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"root-name-statement","schema":"test","input":"Card = Card([Text(\"named\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"Card"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"n"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"duplicate-ids","schema":"test","input":"root = Card([a])\na = Text(\"first\")\na = Text(\"second\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fir"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":53,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"only-prose","schema":"test","input":"Here is your UI, it will appear below.","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"whitespace","schema":"test","input":" \n\t \n","checkpoints":[{"at":1,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fences-and-prose","schema":"test","input":"Sure! Here it is:\n```openui\nroot = Card([a])\na = Text(\"fenced\")\n```\nAnything else?","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"f"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":82,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiple-fences","schema":"test","input":"```\nroot = Card([a])\n```\nand\n```\na = Text(\"second block\")\n```","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"secon"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second bloc"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unclosed-fence","schema":"test","input":"```openui\nroot = Card([a])\na = Text(\"str","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"str"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fence-in-string","schema":"test","input":"root = Card([a])\na = Text(\"use ``` to fence\")","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"u"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use `"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` t"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fe"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"comments","schema":"test","input":"root = Card([a]) // trailing\n# full line\na = Text(\"not // a comment # here\")\n// done","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not /"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a com"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment #"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"crlf","schema":"test","input":"root = Card([a])\r\na = Text(\"windows\")\r\n","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"wind"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"string-escapes","schema":"test","input":"root = Card([a, b, c, d])\na = Text(\"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83d\\ude00\")\nb = Text('single \\' quote \\n esc \\q')\nc = Text(\"bad \\x escape\")\nd = Text(\"emoji 😀 and é and 漢字\")","checkpoints":[{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nqu"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ uni"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":112,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' qu"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":128,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x"},"partial":true,"hasDynamicProps":false,"statementId":"c"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["d"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":160,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":176,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":true,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and"},"partial":true,"hasDynamicProps":false,"statementId":"d"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":187,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and é and 漢字"},"partial":false,"hasDynamicProps":false,"statementId":"d"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"emoji-outside-strings","schema":"test","input":"root = Card([a]) 😀\na = Text(\"ok\") ✅","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-string","schema":"test","input":"root = Card([a])\na = Text(\"streaming tex","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"s"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"strea"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming tex"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-escape","schema":"test","input":"root = Card([a])\na = Text(\"ends with \\","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with \\"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"numbers","schema":"test","input":"root = Card([Chart([\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"], [-3, 1.5, 1e3, 007, -0, 2.5e-3])])\n$x = 1e\n$y = 1E+2\n$z = 3.","checkpoints":[{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Chart"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,0]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,{"k":"Member","obj":{"k":"Num","v":2},"field":"?"},null]},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":81,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$x":null},"queryStatements":[],"mutationStatements":[]}},{"at":99,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$x":null,"$y":100},"queryStatements":[],"mutationStatements":[]}},{"at":106,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$x":null,"$y":100,"$z":{"k":"Member","obj":{"k":"Num","v":3},"field":"?"}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"operators","schema":"test","input":"$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])","checkpoints":[{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$a":1},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":""}}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"ye"},"else":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":88,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":92,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiline-ternary","schema":"test","input":"$on = true\nroot = Card([t])\nt = Text($on\n ? \"enabled\"\n : \"disabled\")","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"StateRef","n":"$on"}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"en"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabl"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabled"}}},"partial":false,"hasDynamicProps":true,"statementId":"t"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}}]},{"name":"member-index","schema":"test","input":"$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"row":null}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":""}]}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":null,"?":null}]}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key":null}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"row"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":139,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key x"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"builtins","schema":"test","input":"$items = [3, 1, 2]\nroot = Card([Text(\"\" + @Count($items)), Text(\"\" + @Sum($items)), Text(@Round(2.555, 2) + \"\")])\nbare = Count($items)","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3]},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Count"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Count"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Su"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Su"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Comp","name":"Round","args":[]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":134,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"actions","schema":"test","input":"$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))","checkpoints":[{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Card"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1","b2","b3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Ac","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Ph","n":"ToAssistant"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ToAssistant","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":126,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Ph","n":"Res"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Res","b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":162,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["But"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Action"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":198,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https:"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":215,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https://openui.com"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b3"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}}]},{"name":"each","schema":"test","input":"$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))","checkpoints":[{"at":10,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[]},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a"}]},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["f","f"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"ti":null,"?":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b"}]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["Each"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ph","n":"t"}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[],"mappedProps":{}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":110,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":113,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"query-mutation","schema":"test","input":"$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])","checkpoints":[{"at":19,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["users"],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":57,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"Null"}],["?",{"k":"Null"}]]},"defaultsAST":null,"refreshAST":null,"deps":["$q"],"complete":true}],"mutationStatements":[]}},{"at":76,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":null,"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":95,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["save"],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":114,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"Null"}],["?",{"k":"Null"}]]}}]}},{"at":133,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":152,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"le"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":171,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["B"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":190,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Actio"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":209,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Ph","n":"Run"}]}]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Run"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":221,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"users","refType":"query"}]}]}]}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}}]},{"name":"state-query","schema":"test","input":"$data = Query(\"get\", {})\nroot = Card([Text(\"x\")])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Qu","Qu"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":null},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":""},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":25,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}}]},{"name":"inline-query","schema":"test","input":"root = Card([Text(Query(\"get\", {}))])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Qu"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":37,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"assignment","schema":"test","input":"$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Inpu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"na"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"excess-args","component":"Input","path":"","message":"Input takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$valu"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$valu":null},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$value"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$value":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"object-key-order","schema":"test","input":"$o = {b: 1, 2: \"two\", a: 3, 1: \"one\", \"10\": 10}\nroot = Card([Text(\"x\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{}},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"tw","b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"two","b":1,"a":null}},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":null,"2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":null,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-commas","schema":"test","input":"root = Card([Text(\"a\") Text(\"b\"), Text(\"c\"),])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":46,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"lowercase-builtin-name","schema":"test","input":"root = Card([Text(@first([1]))])","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fi"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["first"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-tokens","schema":"test","input":"root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"combining-characters","schema":"test","input":"root = Card([Text(\"e\\u0301 cafe\\u0301\"), Text(\"한국어\"), Text(\"ok\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u03"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é caf"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u0301 cafe\\u030"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-call","schema":"test","input":"root = Card([a, b])\na = Text(\"one\")\nb = Button(\"tw","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","b"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Butto"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Button","props":{"label":"tw"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-object","schema":"test","input":"root = Card([Chart([\"a\"], [1], {unit: \"k","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":null,"?":null}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"k"}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cloud-envelope","schema":"chat","input":"]]>openui:content?thesys=true\n```openui-lang\nroot = Card([h, t])\nh = CardHeader(\"Q3\", \"Revenue\")\nt = TextContent(\"Up 12%\")\n```\n]]>openui:end","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["h"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car","t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3"},"partial":true,"hasDynamicProps":false,"statementId":"h"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["TextCon"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":true,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":true,"hasDynamicProps":false,"statementId":"t"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":140,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}] +[{"name":"chat-example-1","schema":"chat","input":"Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }","checkpoints":[{"at":607,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["highlights","statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1214,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1821,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","valu":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ov2","ov3","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":13,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2428,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[],"isFoldable":null},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secLandmarks","secFood","secWhen","f","actionBtns","src1","src2"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3035,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":null,"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["lm1tagIcon","lm2","lm3","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3642,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["lm3body","lm3tag","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":33,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"lm3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["foodCards","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4856,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Sh"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":45,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5463,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"P"},"partial":true,"hasDynamicProps":false,"statementId":"sp2"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sp3","tabSummer","actionBtns","src1","src2"],"orphaned":[],"statementCount":51,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6070,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Sein"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["su2","su3","actionBtns","src1","src2"],"orphaned":[],"statementCount":55,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6677,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":true,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":true,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{}},"partial":true,"hasDynamicProps":false,"statementId":"btn2"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btn3","src1","src2"],"orphaned":[],"statementCount":60,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7277,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":false,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"springList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":false,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":false,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":false,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":false,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{"type":"continue_conversation","context":"Show me the best hotels in Paris"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn2"},{"type":"element","typeName":"Button","props":{"label":"Build a Paris Itinerary","action":{"type":"continue_conversation","context":"Build a 5-day Paris itinerary for me"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn3"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[{"title":"Paris Travel Guide 2025","sourceName":"Travel and Tour World","url":"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/"},{"title":"Best Things to Do in Paris 2026","sourceName":"Time Out Paris","url":"http://www.timeout.fr/paris/en/for-tourists"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-2","schema":"chat","input":"Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")","checkpoints":[{"at":510,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpi1icon","kpi1rhs","kpi2","kpi3","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi1lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1020,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3icon","kpi3rhs","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":13,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi3lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1530,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabGrowth","t","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2040,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["retentio","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2550,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":35,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3060,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tab","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3570,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Sta"]},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":47,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4080,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":null,"body":[]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["supportIcon","supportMetric","supportChart","supportList","cardMarketing","actionButtons"],"orphaned":[],"statementCount":51,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"supportHeader"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4590,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","rig":null}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sup2","sup3","cardMarketing","actionButtons"],"orphaned":[],"statementCount":58,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["marketingMetric","marketingChart","marketingList","actionButtons"],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":true,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":true,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":true,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":true,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Co"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["mkt3","actionButtons"],"orphaned":[],"statementCount":70,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6118,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":false,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":false,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":false,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":false,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Cost per Lead","right":"$48.20","rightVariant":"number"},{"left":"Top Channel","right":"Organic Search","rightVariant":"text"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Break Down by Channel","action":{"type":"continue_conversation","context":"Break down this month's revenue by acquisition channel"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnChannels"},{"type":"element","typeName":"Button","props":{"label":"Forecast Next Quarter","action":{"type":"continue_conversation","context":"Forecast revenue and active users for next quarter"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnForecast"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionButtons"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":74,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-3","schema":"chat","input":"Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)","checkpoints":[{"at":361,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas"},"partial":true,"hasDynamicProps":false,"statementId":"header"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","inspoCards","form"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":722,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["i","insp2","form"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"insp1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1083,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2","form"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1444,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":null,"size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2icon","form"],"orphaned":[],"statementCount":11,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1805,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btnSkip","fcDestination","fcDates","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":15,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2166,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Fo","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":19,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2527,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tr1","tr2","tr3","tr4","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2888,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["oc2","oc3","oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":29,"errors":[{"code":"missing-required","component":"OptionCard","path":"/title","message":"missing required field \"/title\" — signature: OptionCard(value*: string, title*: string, subtitle: string, topContent, disabled: boolean)","statementId":"oc1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":34,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fcNotes"],"orphaned":[],"statementCount":39,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"fcStay"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3971,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":null},"partial":true,"hasDynamicProps":false,"statementId":"ch3"}],"rules":{},"defaultValue":["hotel"]},"partial":true,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":true,"hasDynamicProps":false,"statementId":"fcStay"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ch4","fcNotes"],"orphaned":[],"statementCount":46,"errors":[{"code":"missing-required","component":"Icon","path":"/name","message":"missing required field \"/name\" — signature: Icon(name*: string, category: string)","statementId":"ch3icon"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4322,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":false,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":false,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":{"type":"element","typeName":"Icon","props":{"name":"home","category":"home"},"partial":false,"hasDynamicProps":false,"statementId":"ch3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch3"},{"type":"element","typeName":"ChipItem","props":{"value":"camping","label":"Camping / Glamping","icon":{"type":"element","typeName":"Icon","props":{"name":"tent","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"ch4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch4"}],"rules":{},"defaultValue":["hotel"]},"partial":false,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fcStay"},{"type":"element","typeName":"FormControl","props":{"label":"Special Requests or Notes","input":{"type":"element","typeName":"TextArea","props":{"name":"special-requests","placeholder":"e.g. vegetarian meals, wheelchair access, honeymoon surprise...","rows":4},"partial":false,"hasDynamicProps":false,"statementId":"notesArea"},"hint":"Any dietary needs, accessibility requirements, or specific interests?"},"partial":false,"hasDynamicProps":false,"statementId":"fcNotes"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":50,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-4","schema":"chat","input":"Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }","checkpoints":[{"at":218,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Ene"},"partial":true,"hasDynamicProps":false,"statementId":"header"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":436,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to w"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":654,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["v1body","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"v1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":872,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":null,"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v1icon","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1090,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":null,"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v2tag","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1308,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["CompositeCard","src1","src2"],"orphaned":[],"statementCount":14,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1526,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1icon","t1body","t1tags","t1btn","t2","src1","src2"],"orphaned":[],"statementCount":16,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t1h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1744,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Wa"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2","src1","src2"],"orphaned":[],"statementCount":20,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1962,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2icon","t2body","t2tags","t2btn","src1","src2"],"orphaned":[],"statementCount":22,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t2h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":[]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2btn","src1","src2"],"orphaned":[],"statementCount":25,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2398,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceN":null}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2615,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":false,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":false,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},{"title":"Sajan Re (Official Music Video)","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=COUSCnFazzc"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-5","schema":"chat","input":"Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")","checkpoints":[{"at":37,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":74,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["title","tbl","followUps"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":111,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":""},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tbl","followUps"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":148,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":185,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs","users","followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":222,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Pyth"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years","followUps"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":259,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["years","followUps"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":296,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":333,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu1"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":370,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me m"},"partial":true,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu2"],"orphaned":[],"statementCount":8,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":407,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["FollowUpItem"],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":442,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"},{"type":"element","typeName":"FollowUpItem","props":{"text":"Show me a JavaScript comparison"},"partial":false,"hasDynamicProps":false,"statementId":"fu2"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"basic","schema":"test","input":"root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Bu"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Button","path":"/label","message":"missing required field \"/label\" — signature: Button(label*: string, action, variant: \"primary\"|\"secondary\")","statementId":"b1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-required","schema":"test","input":"root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["B"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Button"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":51,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"null-required-with-default","schema":"test","input":"root = Card([t1])\nt1 = Text(null)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"required-default-fills","schema":"test","input":"root = Card([x])\nx = Tagged(1, true, \"x\", null)","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tag"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":null,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-component","schema":"test","input":"root = Card([Mystery(\"a\"), Text(\"b\")])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mys"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mystery"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"excess-args","schema":"test","input":"root = Card([Text(\"a\", \"m\", \"extra\", 4)])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":41,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"type-mismatch-scalar","schema":"test","input":"root = Card([Text(42)], 7)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/title","message":"field \"/title\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-mismatch","schema":"test","input":"root = Card([Text(\"a\", \"xl\"), Button(\"b\", null, \"tertiary\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Button"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"terti"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"tertiary"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/size","message":"field \"/size\" expects one of [\"s\", \"m\", \"l\"] but got \"xl\"","statementId":"root"},{"code":"type-mismatch","component":"Button","path":"/variant","message":"field \"/variant\" expects one of [\"primary\", \"secondary\"] but got \"tertiary\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-partial-deferred","schema":"test","input":"root = Card([Text(\"a\", \"x","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"integer-boolean-const","schema":"test","input":"root = Card([x])\nx = Tagged(1.5, \"yes\", \"y\", \"loud\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tagg"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":{"k":"Member","obj":{"k":"Num","v":1},"field":"?"},"tone":"neutral"},"partial":true,"hasDynamicProps":true,"statementId":"x"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"loud"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"loud"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"},{"code":"type-mismatch","component":"Tagged","path":"/kind","message":"field \"/kind\" expects one of [\"x\"] but got \"y\"","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"nested-object","schema":"test","input":"root = Card([c1, c2, c3])\nc1 = Chart([\"a\"], [1], {unit: \"kg\"})\nc2 = Chart([\"a\"], [1], {scale: 2})\nc3 = Chart([\"a\"], [1], {unit: 5, scale: \"big\"})","checkpoints":[{"at":13,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c1","c2","c3"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"un":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":65,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":78,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":91,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scal":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c2"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":104,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":117,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":130,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":143,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":145,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c3"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"},{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"array-items-pruned","schema":"test","input":"root = Card([Chart([\"a\", 2, \"c\"], [1, \"x\", 3])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"element-in-data-slot","schema":"test","input":"root = Card([Chart([Text(\"a\")], [1])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unresolved-and-orphaned","schema":"test","input":"root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a","miss"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":58,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cycle","schema":"test","input":"root = Card([a])\na = Card([b])\nb = Card([a])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"b"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"self-reference","schema":"test","input":"root = Card([root])","checkpoints":[{"at":2,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["r"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["roo"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"no-root-first-component","schema":"test","input":"x = 1\nmain = Card([Text(\"a\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["main"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"main"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"root-name-statement","schema":"test","input":"Card = Card([Text(\"named\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"Card"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"n"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"duplicate-ids","schema":"test","input":"root = Card([a])\na = Text(\"first\")\na = Text(\"second\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fir"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":53,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"only-prose","schema":"test","input":"Here is your UI, it will appear below.","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"whitespace","schema":"test","input":" \n\t \n","checkpoints":[{"at":1,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fences-and-prose","schema":"test","input":"Sure! Here it is:\n```openui\nroot = Card([a])\na = Text(\"fenced\")\n```\nAnything else?","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"f"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":82,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiple-fences","schema":"test","input":"```\nroot = Card([a])\n```\nand\n```\na = Text(\"second block\")\n```","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"secon"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second bloc"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unclosed-fence","schema":"test","input":"```openui\nroot = Card([a])\na = Text(\"str","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"str"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fence-in-string","schema":"test","input":"root = Card([a])\na = Text(\"use ``` to fence\")","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"u"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use `"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` t"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fe"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"comments","schema":"test","input":"root = Card([a]) // trailing\n# full line\na = Text(\"not // a comment # here\")\n// done","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not /"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a com"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment #"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"crlf","schema":"test","input":"root = Card([a])\r\na = Text(\"windows\")\r\n","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"wind"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"string-escapes","schema":"test","input":"root = Card([a, b, c, d])\na = Text(\"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83d\\ude00\")\nb = Text('single \\' quote \\n esc \\q')\nc = Text(\"bad \\x escape\")\nd = Text(\"emoji 😀 and é and 漢字\")","checkpoints":[{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nqu"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ uni"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":112,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' qu"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":128,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x"},"partial":true,"hasDynamicProps":false,"statementId":"c"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["d"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":160,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":176,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":true,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and"},"partial":true,"hasDynamicProps":false,"statementId":"d"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":187,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and é and 漢字"},"partial":false,"hasDynamicProps":false,"statementId":"d"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"emoji-outside-strings","schema":"test","input":"root = Card([a]) 😀\na = Text(\"ok\") ✅","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-string","schema":"test","input":"root = Card([a])\na = Text(\"streaming tex","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"s"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"strea"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming tex"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-escape","schema":"test","input":"root = Card([a])\na = Text(\"ends with \\","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with \\"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"numbers","schema":"test","input":"root = Card([Chart([\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"], [-3, 1.5, 1e3, 007, -0, 2.5e-3])])\n$x = 1e\n$y = 1E+2\n$z = 3.","checkpoints":[{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Chart"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,0]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,{"k":"Member","obj":{"k":"Num","v":2},"field":"?"},null]},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":81,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$x":null},"queryStatements":[],"mutationStatements":[]}},{"at":99,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$x":null,"$y":100},"queryStatements":[],"mutationStatements":[]}},{"at":106,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$x":null,"$y":100,"$z":{"k":"Member","obj":{"k":"Num","v":3},"field":"?"}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"operators","schema":"test","input":"$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])","checkpoints":[{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$a":1},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":""}}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"ye"},"else":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":88,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":92,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiline-ternary","schema":"test","input":"$on = true\nroot = Card([t])\nt = Text($on\n ? \"enabled\"\n : \"disabled\")","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"StateRef","n":"$on"}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"en"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabl"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabled"}}},"partial":false,"hasDynamicProps":true,"statementId":"t"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}}]},{"name":"member-index","schema":"test","input":"$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"row":null}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":""}]}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":null,"?":null}]}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key":null}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"row"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":139,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key x"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"builtins","schema":"test","input":"$items = [3, 1, 2]\nroot = Card([Text(\"\" + @Count($items)), Text(\"\" + @Sum($items)), Text(@Round(2.555, 2) + \"\")])\nbare = Count($items)","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3]},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Count"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Count"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Su"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Su"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Comp","name":"Round","args":[]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":134,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"actions","schema":"test","input":"$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))","checkpoints":[{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Card"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1","b2","b3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Ac","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Ph","n":"ToAssistant"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ToAssistant","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":126,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Ph","n":"Res"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Res","b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":162,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["But"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Action"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":198,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https:"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":215,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https://openui.com"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b3"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}}]},{"name":"each","schema":"test","input":"$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))","checkpoints":[{"at":10,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[]},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a"}]},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["f","f"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"ti":null,"?":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b"}]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["Each"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ph","n":"t"}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[],"mappedProps":{}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":110,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":113,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"query-mutation","schema":"test","input":"$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])","checkpoints":[{"at":19,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["users"],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":57,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"Null"}],["?",{"k":"Null"}]]},"defaultsAST":null,"refreshAST":null,"deps":["$q"],"complete":true}],"mutationStatements":[]}},{"at":76,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":null,"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":95,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["save"],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":114,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"Null"}],["?",{"k":"Null"}]]}}]}},{"at":133,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":152,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"le"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":171,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["B"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":190,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Actio"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":209,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Ph","n":"Run"}]}]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Run"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":221,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"users","refType":"query"}]}]}]}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}}]},{"name":"state-query","schema":"test","input":"$data = Query(\"get\", {})\nroot = Card([Text(\"x\")])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Qu","Qu"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":null},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":""},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":25,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}}]},{"name":"inline-query","schema":"test","input":"root = Card([Text(Query(\"get\", {}))])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Qu"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":37,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"assignment","schema":"test","input":"$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Inpu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"na"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"excess-args","component":"Input","path":"","message":"Input takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$valu"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$valu":null},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$value"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$value":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"object-key-order","schema":"test","input":"$o = {b: 1, 2: \"two\", a: 3, 1: \"one\", \"10\": 10}\nroot = Card([Text(\"x\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{}},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"tw","b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"two","b":1,"a":null}},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":null,"2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":null,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-commas","schema":"test","input":"root = Card([Text(\"a\") Text(\"b\"), Text(\"c\"),])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":46,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"lowercase-builtin-name","schema":"test","input":"root = Card([Text(@first([1]))])","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fi"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["first"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-tokens","schema":"test","input":"root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"combining-characters","schema":"test","input":"root = Card([Text(\"e\\u0301 cafe\\u0301\"), Text(\"한국어\"), Text(\"ok\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u03"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é caf"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u0301 cafe\\u030"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-call","schema":"test","input":"root = Card([a, b])\na = Text(\"one\")\nb = Button(\"tw","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","b"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Butto"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Button","props":{"label":"tw"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-object","schema":"test","input":"root = Card([Chart([\"a\"], [1], {unit: \"k","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":null,"?":null}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"k"}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"data-in-component-slot","schema":"test","input":"root = Card([Text(\"hi\"), { text: \"a\" }, \"b\", 3, [Text(\"x\")], true])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/5","message":"field \"/children/5\" expects Text | Button | Chart but got boolean","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":67,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/5","message":"field \"/children/5\" expects Text | Button | Chart but got boolean","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"data-in-component-slot-via-ref","schema":"test","input":"root = Card(items)\nitems = [{ text: \"a\" }]","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["item"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["items"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["items"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"hoisted-data-def","schema":"hoisted","input":"root = Tree({ label: \"a\" })","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Tr"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Tree","path":"/node","message":"missing required field \"/node\" — signature: Tree(node*: __schema0)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"l":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"labe":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":"a"}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":"a"}},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cloud-envelope","schema":"chat","input":"]]>openui:content?thesys=true\n```openui-lang\nroot = Card([h, t])\nh = CardHeader(\"Q3\", \"Revenue\")\nt = TextContent(\"Up 12%\")\n```\n]]>openui:end","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["h"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car","t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3"},"partial":true,"hasDynamicProps":false,"statementId":"h"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["TextCon"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":true,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":true,"hasDynamicProps":false,"statementId":"t"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":140,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}] From 2d15b1157e60d6bc9bca411ba344c9f858f67f7b Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Mon, 5 Oct 2026 06:24:49 +0530 Subject: [PATCH 13/52] docs(swift-lang): add a README Covers installing the package as a local Swift package, defining components and libraries, generating prompts, rendering streamed output, the chat library, tool providers, the differences from lang-core, and how to regenerate the conformance fixtures. --- packages/swift-lang/README.md | 240 ++++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 packages/swift-lang/README.md diff --git a/packages/swift-lang/README.md b/packages/swift-lang/README.md new file mode 100644 index 0000000000..5cf9b8d7fc --- /dev/null +++ b/packages/swift-lang/README.md @@ -0,0 +1,240 @@ +# OpenUI for Swift + +Native Swift support for OpenUI Lang. Define model-renderable components in Swift, generate prompts from them, parse streamed OpenUI Lang, and render it with SwiftUI on iOS and macOS. + +Two libraries: + +- **`OpenUILang`**: parser, streaming parser, runtime (state, actions, queries), component library definitions and prompt generation. Plain Swift with Foundation. +- **`OpenUISwiftUI`**: the SwiftUI renderer and native views for every component of the OpenUI chat library. + +**Links:** [OpenUI Lang docs](https://openui.com/docs/openui-lang) | [GitHub repo](https://github.com/thesysdev/openui) + +## Install + +Requires Swift 6 and iOS 17 or macOS 14. + +The package lives in `packages/swift-lang` of this repository. Swift Package Manager only resolves packages at the root of a git repository, so for now add it as a local package (File > Add Package Dependencies > Add Local… in Xcode), or in `Package.swift`: + +```swift +dependencies: [ + .package(path: "../openui/packages/swift-lang"), +], +targets: [ + .target(name: "App", dependencies: [.product(name: "OpenUISwiftUI", package: "swift-lang")]), +] +``` + +`OpenUISwiftUI` re-exports `OpenUILang`. + +## Overview + +OpenUI for Swift follows the same model as the JavaScript packages: + +1. **Define components** the model may call, with typed props. +2. **Generate a system prompt** from the component library. +3. **Render streamed output** with `OpenUIRenderer` as OpenUI Lang arrives. + +The parser and runtime are a port of `@openuidev/lang-core`, checked against it with conformance fixtures (see [Testing Locally](#testing-locally)). The built-in chat library uses the same component names, arguments and prompt options as `openuiChatLibrary` from `@openuidev/react-ui`, so one backend prompt, or OpenUI Cloud, can drive web and native clients. + +## Quick Start + +### 1. Define a component + +```swift +import OpenUISwiftUI +import SwiftUI + +let greetingSchema = ComponentSchema( + "Greeting", description: "Greets someone by name", + props: [ + Prop("name", .string), + Prop("mood", .enumeration(["happy", "excited"]), .optional), + ]) + +let greeting = SwiftUIComponent(greetingSchema) { props in + Text("Hello, \(props.text("name"))\(props.string("mood") == "excited" ? "!" : ".")") + .font(.title2) +} +``` + +`props` holds the evaluated arguments, mapped from positional arguments by the order of the schema's props. + +### 2. Create a library + +```swift +let stackSchema = ComponentSchema( + "Stack", description: "Vertical stack", + props: [Prop("children", .array(.union([.component("Greeting"), .component("Stack")])))]) + +let stack = SwiftUIComponent(stackSchema) { props in + OpenUINodes(props.array("children")) +} + +let library = SwiftUILibrary(components: [stack, greeting], root: "Stack") +``` + +### 3. Generate a system prompt + +```swift +let systemPrompt = library.prompt(PromptOptions(additionalRules: ["Keep greetings short."])) +``` + +The prompt matches what `lang-core` generates for the same library. If prompts are built on a server, `library.toSpec()` returns a `LibrarySpec` you can pass to `generateSystemPrompt({ library })` from `@openuidev/lang-core`. + +With OpenUI Cloud, send the config block instead; Cloud builds the prompt on its side. It's the same block `generateSystemPrompt({ cloud: true, library })` returns: + +```swift +let systemMessage = try library.cloudConfig(PromptOptions(additionalRules: ["Keep greetings short."])) +``` + +### 4. Render streamed output + +```swift +struct MessageView: View { + let text: String + let isStreaming: Bool + + var body: some View { + OpenUIRenderer(response: text, isStreaming: isStreaming, library: library) { event in + // Buttons, follow-ups and forms continue the conversation through here. + print(event.type, event.humanFriendlyMessage, event.formState ?? [:]) + } + } +} +``` + +Pass the full response text so far on every chunk; the renderer only re-parses what changed. OpenUI Cloud responses wrap the program in `]]>openui:content` and `]]>openui:end` markers; pass them through as they are, like the JavaScript renderers do. + +## The chat library + +`OpenUIChatLibrary.library` renders every `openuiChatLibrary` component natively: cards and text, Markdown, callouts, code, images and galleries, Swift Charts (bar, line, area, horizontal bar, pie, radial, single stacked bar, scatter) and a radar chart, tables and the editable table, forms (inputs, text areas, selects, date pickers, sliders, check boxes, radios, switches, chips, option cards) with validation, buttons and icon buttons, lists and follow-ups, steps, tabs, accordions, sections, carousels, tags, entity lists and the card blocks. + +```swift +OpenUIRenderer(response: text, isStreaming: isStreaming, library: OpenUIChatLibrary.library) { event in + send(event.humanFriendlyMessage) +} + +// The prompt a react-ui app sends with openuiChatPromptOptions: +let prompt = OpenUIChatLibrary.library.prompt(ChatComponents.promptOptions) +// Or for OpenUI Cloud: +let systemMessage = try OpenUIChatLibrary.library.cloudConfig(ChatComponents.promptOptions) +``` + +The views follow react-ui's layouts and behavior rather than restyling them: card blocks use the same responsive grid (one column on phones), tabs and sections follow the stream until the user picks one, charts use react-ui's palette and curves, and `[n]` citations resolve against the card's sources. Lucide icon names map to SF Symbols with the same category fallbacks. Spacing, fills and corner radii come from `OpenUITheme`, which follows react-ui's design tokens; override it with `.environment(\.openUITheme, theme)`. + +The schemas in `ChatComponents` live in `OpenUILang`, without SwiftUI, so a Swift server can build the chat prompt too. They're generated from `openuiChatLibrary` (see [Testing Locally](#testing-locally)). + +## API Reference + +### Component Definition + +| API | Description | +| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ComponentSchema(name, description:, props:)` | A component's contract with the model: props in positional order. | +| `Prop(name, type, presence, binding:, description:)` | A prop. `presence` is `.required` (default), `.optional` or `.defaulted(value)`. `binding: true` marks a two-way `$state` binding, shown as `$binding` in the prompt. | +| `PropType` | `.string`, `.number`, `.boolean`, `.any`, `.enumeration`, `.literal`, `.array(_, minItems:)`, `.object([Prop])`, `.record`, `.component(name)`, `.union`, `.named(name, type)`, `.actionExpression` | +| `SwiftUIComponent(schema) { props in … }` | Pairs a schema with the SwiftUI view that renders it. | +| `SwiftUILibrary(components:, root:, componentGroups:)` | A library (`Library`). | + +Schemas serialize to the same JSON Schema `lang-core` libraries produce: `schema.jsonSchema`, `library.toJSONSchema()`. + +### Rendering + +| API | Description | +| ---------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | +| `OpenUIRenderer(response:isStreaming:library:initialState:toolProvider:queryLoader:onAction:onStateUpdate:onParseResult:onError:)` | Renders a response. `queryLoader` replaces the small spinner shown while queries load. | +| `OpenUINode(value)` / `OpenUINodes(values)` | Render child props (elements, arrays, text) inside a component. | +| `ComponentProps` | `string`, `text`, `number`, `bool`, `array`, `elements`, `children` accessors that tolerate partial values while streaming. | + +### Errors + +`onError` receives the same structured errors as react-lang's `onError`, for an automated correction loop: parser validation errors with fix hints (available components, the expected signature), `parse-failed` when a finished response has no root, and failed `Query`/`Mutation` calls. Errors are reported once the response finishes streaming, and `onError([])` is called when they clear or the next response starts. `OpenUIError.jsonRepresentation` gives the same JSON shape as lang-core's `OpenUIError`. + +### Context Helpers + +Components read the renderer state from the environment: + +```swift +@Environment(OpenUIContext.self) private var context +@Environment(\.openUIFormName) private var form +@Environment(FormValidation.self) private var validation: FormValidation? +``` + +| API | Description | +| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| `context.triggerAction(label, form:, action:)` | Runs an action: an `Action([...])` plan, a legacy action object, or (with no action) continues the conversation with `label`. | +| `context.stateField(name:binding:form:)` | The field a component reads and writes: a `$state` binding when the prop is bound, otherwise the form field. | +| `context.isStreaming`, `context.isQueryLoading` | Streaming and query status. | + +### Form Validation + +`Form` provides a `FormValidation` to its fields. Fields register `rules` (`{ required: true, minLength: 3, email: true, … }`), primary buttons validate the form before firing their action, and `FormControl` shows the error. + +### Parser, prompt and runtime (`OpenUILang`) + +| API | Description | +| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| `Parser(schema:rootName:)` | Batch parser from a library JSON Schema. `parse(_:)`, `makeStreamParser()`. | +| `StreamParser` | `push(_:)` a chunk or `set(_:)` the full text so far; returns the latest `ParseResult`. | +| `OpenUIRuntime` | Streaming parse, store, prop evaluation, form fields, actions and error reporting, without UI (react-lang's `useOpenUIState`). | +| `generatePrompt(_:)`, `library.prompt(_:)` | Build the system prompt. | +| `generateCloudConfig(library:promptOptions:instructions:)`, `library.cloudConfig(_:instructions:)` | OpenUI Cloud's config block (`generateSystemPrompt({ cloud: true })`). | +| `mergeStatements(_:_:rootId:)` | Edit mode: applies a patch program to an existing one. | +| `evaluate(_:_:)`, `Store`, `QueryManager` | Lower-level runtime pieces. | + +## Tool Provider Support (Queries & Mutations) + +`Query(...)` and `Mutation(...)` statements call tools through a `ToolProvider`: + +```swift +let tools = FunctionToolProvider([ + "list_tickets": { args in + let status = args["status"]?.stringValue ?? "open" + return ["rows": [["id": "T-1", "status": .string(status)]]] + } +]) + +OpenUIRenderer(response: text, library: library, toolProvider: tools) +``` + +Conform your own type to `ToolProvider` for MCP or other backends; `extractToolResult(_:)` unwraps MCP `callTool` results. + +## JSON Schema Output + +`library.toJSONSchema()` produces the same document as `library.toJSONSchema()` in `lang-core` (component schemas under `$defs`, props in positional order), and the parser compiles positional parameters from it. When reading a schema from JSON, use `JSON.parse(_:)`, which keeps object key order. + +## Differences from lang-core + +- A component inside `@Each` or a ternary that binds a reactive prop to `$state` writes the typed value. In `lang-core` that binding is re-evaluated and nested, so typing writes `undefined`. +- Composite values (arrays, objects) have no identity in Swift, so `==` between two of them is always false. In JavaScript it's true only for the same instance. +- Prop evaluation and SwiftUI views can't throw, so `onError` never reports `runtime-error` or `render-error`. +- `$$` math in text content shows as source; there's no native TeX renderer. +- Not ported: `jsonToOpenUI`, the deprecated `enrichErrors` (its hints are in `onError`), and the server-side `artifactTool` from `@openuidev/lang-core/cloud`. + +## Testing Locally + +Running the tests needs Xcode (the Command Line Tools alone don't include the testing frameworks). + +```bash +cd packages/swift-lang +swift test +swift format lint --strict -r Sources Tests Package.swift +``` + +The conformance fixtures in `Tests/OpenUILangTests/Fixtures` are generated from the TypeScript packages, which are the source of truth. They cover batch and streaming parsing, prop evaluation, prompts, OpenUI Cloud config, edit-mode merging, error hints and the chat library schemas. After changing `lang-core` or the chat library, rebuild and regenerate them, and regenerate `ChatComponents.swift` when the chat library changed: + +```bash +pnpm run build:packages +node packages/swift-lang/Scripts/generate-fixtures.mjs +node packages/swift-lang/Scripts/generate-chat-components.mjs +``` + +CI regenerates the fixtures from a fresh build and fails if they differ, so drift in `lang-core` or the chat library shows up as a failing check. + +## Documentation + +Full OpenUI Lang documentation is at [openui.com/docs/openui-lang](https://openui.com/docs/openui-lang). + +## License + +MIT From 4d2370c6108a1d57b6da40ccb49e35edb8e64bd6 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Mon, 5 Oct 2026 06:24:49 +0530 Subject: [PATCH 14/52] ci: build and test the Swift package Runs on changes to packages/swift-lang, lang-core sources or the chat library: builds, tests and lints the package on macOS, and regenerates the conformance fixtures from the TypeScript packages to fail when the Swift port and lang-core drift apart. --- .github/workflows/build-swift.yml | 74 ++++++++++++++++++++++++++++++ packages/swift-lang/.gitattributes | 4 ++ 2 files changed, 78 insertions(+) create mode 100644 .github/workflows/build-swift.yml create mode 100644 packages/swift-lang/.gitattributes diff --git a/.github/workflows/build-swift.yml b/.github/workflows/build-swift.yml new file mode 100644 index 0000000000..326daf307c --- /dev/null +++ b/.github/workflows/build-swift.yml @@ -0,0 +1,74 @@ +name: Build Swift + +on: + push: + branches: [main] + paths: + - "packages/swift-lang/**" + - "packages/lang-core/src/**" + - "packages/react-ui/src/genui-lib/**" + - ".github/workflows/build-swift.yml" + pull_request: + branches: [main] + paths: + - "packages/swift-lang/**" + - "packages/lang-core/src/**" + - "packages/react-ui/src/genui-lib/**" + - ".github/workflows/build-swift.yml" + +permissions: + contents: read + +jobs: + swift: + runs-on: macos-15 + defaults: + run: + working-directory: packages/swift-lang + steps: + - uses: actions/checkout@v4 + + - name: Build + run: swift build + + - name: Test + run: swift test + + - name: Lint + run: swift format lint --strict -r Sources Tests Package.swift + + - name: Build for iOS + run: xcodebuild build -scheme OpenUI-Package -destination "generic/platform=iOS Simulator" -quiet + + # The Swift port is checked against fixtures generated from lang-core and the + # chat library. Fail when they no longer match what the TypeScript produces. + fixtures: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v6 + - uses: actions/setup-node@v4 + with: + node-version: v24.21.0 + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build lang-core and react-ui + run: pnpm --filter "@openuidev/react-ui..." --workspace-concurrency=1 run build + + - name: Regenerate fixtures + run: node packages/swift-lang/Scripts/generate-fixtures.mjs + env: + OPENUI_TELEMETRY_DISABLED: "1" + + # Status rather than diff, so a newly generated fixture file counts too. + - name: Check fixtures are up to date + run: | + fixtures="packages/swift-lang/Tests/OpenUILangTests/Fixtures packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures" + if [ -n "$(git status --porcelain -- $fixtures)" ]; then + git status --short -- $fixtures + git diff -- $fixtures | head -100 + exit 1 + fi diff --git a/packages/swift-lang/.gitattributes b/packages/swift-lang/.gitattributes new file mode 100644 index 0000000000..7695fe78a1 --- /dev/null +++ b/packages/swift-lang/.gitattributes @@ -0,0 +1,4 @@ +# Generated from the TypeScript packages (see Scripts/); collapsed in diffs. +Tests/OpenUILangTests/Fixtures/*.json linguist-generated=true +Tests/OpenUISwiftUITests/Fixtures/*.json linguist-generated=true +Sources/OpenUILang/ChatComponents.swift linguist-generated=true From 7b04f84804e24811de96a4189e1dda061f20ef51 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 02:25:24 +0530 Subject: [PATCH 15/52] fix(swift-lang): render a finished response when the renderer is nested The renderer's content was a Group, and a Group's modifiers apply to its children. Before the first parse there are none, so inside a stack or a lazy list the initial onChange never ran and a response that doesn't change afterwards (a restored chat message) stayed blank. Streaming hid it, since each new chunk triggers an update. --- .../Sources/OpenUISwiftUI/OpenUIRenderer.swift | 5 ++++- .../OpenUISwiftUITests/RendererTests.swift | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift index 977705ef51..aa1c2c67c5 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift @@ -56,7 +56,10 @@ public struct OpenUIRenderer: View { public var body: some View { let _ = syncHandlers() - Group { + // Not a Group: modifiers on a Group apply to its children, and before the + // first update there are none, so a nested renderer whose response never + // changes (a restored message) would never run the onChange below. + VStack(alignment: .leading, spacing: 0) { if let root = context.root { OpenUIElementView(element: root) .opacity(context.isQueryLoading ? 0.7 : 1) diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index f77c82bd80..d13796e269 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -217,6 +217,24 @@ import Testing #expect(textFields(host).first { $0.isEditable } === field) } + /// A finished response inside a stack (a restored chat message) must render + /// even though its text never changes after the view appears. + @Test func rendersAFinishedResponseNestedInAStack() { + let input = Self.examples[1].input + let host = NSHostingView( + rootView: VStack(alignment: .leading) { + Text("Earlier message") + OpenUIRenderer(response: input, library: OpenUIChatLibrary.library) + } + .frame(width: 420)) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 420, height: 600), styleMask: [.borderless], + backing: .buffered, defer: false) + window.contentView = host + RunLoop.main.run(until: Date().addingTimeInterval(0.3)) + #expect(host.fittingSize.height > 400, "rendered \(host.fittingSize)") + } + @Test func passesParseResultsAndErrorsToTheHost() { final class Received { var parseResults = 0 From 1e9dbf1034beed0a1b1bb1e6f9fdee7a6a86b877 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 02:55:20 +0530 Subject: [PATCH 16/52] feat(swift-lang): animate streamed responses like react-ui - Charts use react-ui's motion: bars grow in, lines and areas draw from left to right, pie/radial/radar/scatter fade in, and values glide to new positions on the dataMorph spring (stiffness 480, damping 44) as data streams in. Points are keyed by series and label so they move rather than redraw. - Newly streamed nodes fade in; nodes keep their identity, so nothing else re-animates. Tabs, accordions and sections animate when they follow the stream. - Charts that have no data yet and loading images show react-ui's pulsing skeleton; images fade in when they load. - Card grids are a Layout that reads the offered width, so they lay out correctly on the first frame instead of re-flowing. Everything respects Reduce Motion. --- .../Components/CardComponents.swift | 71 +++++++--- .../Components/ChartComponents.swift | 64 ++++++--- .../Components/ContentComponents.swift | 24 ++-- .../Components/LayoutComponents.swift | 18 +-- .../Sources/OpenUISwiftUI/Motion.swift | 130 ++++++++++++++++++ .../Sources/OpenUISwiftUI/OpenUINode.swift | 4 +- .../OpenUISwiftUI/OpenUIRenderer.swift | 1 + 7 files changed, 263 insertions(+), 49 deletions(-) create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Motion.swift diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift index df7a7a6808..0770d73b6a 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift @@ -85,29 +85,68 @@ struct ResponsiveCardGrid: View { var responsive = true var spacing: CGFloat = 12 @ViewBuilder let cell: (Int) -> Cell - @State private var width: CGFloat = 0 var body: some View { - VStack(spacing: spacing) { - ForEach(rows, id: \.self) { row in - HStack(alignment: .top, spacing: spacing) { - ForEach(row, id: \.self) { index in - cell(index).frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) - } - } - .fixedSize(horizontal: false, vertical: true) + CardGridLayout(maxPerRow: maxPerRow, responsive: responsive, spacing: spacing) { + ForEach(0.. CGSize { + guard let width = proposal.width, width.isFinite else { + // No width to fit (e.g. measuring an ideal size): one column. + let sizes = subviews.map { $0.sizeThatFits(.unspecified) } + let height = sizes.map(\.height).reduce(0, +) + spacing * CGFloat(max(sizes.count - 1, 0)) + return CGSize(width: sizes.map(\.width).max() ?? 0, height: height) + } + let height = rows(subviews.count, width).reduce(into: CGFloat(0)) { total, row in + total += rowHeight(row, subviews, width) + } + return CGSize( + width: width, height: height + spacing * CGFloat(max(rowCount(subviews.count, width) - 1, 0))) + } + + func placeSubviews( + in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout () + ) { + var y = bounds.minY + for row in rows(subviews.count, bounds.width) { + let width = cellWidth(row.count, bounds.width) + let height = rowHeight(row, subviews, bounds.width) + for (column, index) in row.enumerated() { + subviews[index].place( + at: CGPoint(x: bounds.minX + CGFloat(column) * (width + spacing), y: y), + proposal: ProposedViewSize(width: width, height: height)) + } + y += height + spacing } } - /// Cell indices per row. Until the width is known, one per row. - private var rows: [[Int]] { + private func cellWidth(_ columns: Int, _ width: CGFloat) -> CGFloat { + (width - spacing * CGFloat(columns - 1)) / CGFloat(columns) + } + + private func rowHeight(_ row: [Int], _ subviews: Subviews, _ width: CGFloat) -> CGFloat { + let proposal = ProposedViewSize(width: cellWidth(row.count, width), height: nil) + return row.map { subviews[$0].sizeThatFits(proposal).height }.max() ?? 0 + } + + private func rowCount(_ count: Int, _ width: CGFloat) -> Int { rows(count, width).count } + + /// Subview indices per row, using react-ui's breakpoints. + private func rows(_ count: Int, _ width: CGFloat) -> [[Int]] { let perRow: [Int] if responsive && width <= 480 { perRow = Array(repeating: 1, count: count) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift index a309880864..809da96bce 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift @@ -2,9 +2,11 @@ import Charts import OpenUILang import SwiftUI -/// One value of one series at one category label. -private struct SeriesPoint: Identifiable { - let id: Int +/// One value of one series at one category label. The id is the series and +/// label (not the position), so a value that changes while streaming moves to +/// its new place instead of being redrawn. +private struct SeriesPoint: Identifiable, Equatable { + let id: String let label: String let series: String let value: Double @@ -20,7 +22,9 @@ private func seriesPoints(_ props: ComponentProps) -> [SeriesPoint] { for (index, value) in series.array("values").enumerated() where index < labels.count { guard let number = value.numberValue, number.isFinite else { continue } points.append( - SeriesPoint(id: points.count, label: labels[index], series: name, value: number)) + SeriesPoint( + id: "\(name)\u{1}\(labels[index])\u{1}\(index)", label: labels[index], series: name, + value: number)) } } return points @@ -94,20 +98,30 @@ extension View { } } +/// Sizes a chart, puts its legend below, and shows a pulsing placeholder +/// while the response streams in before any of its values have. private struct ChartFrame: View { let props: ComponentProps + let isEmpty: Bool let content: Content + @Environment(OpenUIContext.self) private var context @Environment(\.openUITheme) private var theme - init(_ props: ComponentProps, @ViewBuilder content: () -> Content) { + init(_ props: ComponentProps, isEmpty: Bool, @ViewBuilder content: () -> Content) { self.props = props + self.isEmpty = isEmpty self.content = content() } var body: some View { - content - .frame(height: props.number("height").map { CGFloat($0) } ?? theme.chartHeight) - .chartLegend(position: .bottom, alignment: .leading) + let height = props.number("height").map { CGFloat($0) } ?? theme.chartHeight + if isEmpty && (context.isStreaming || context.isQueryLoading) { + SkeletonBlock(height: height, cornerRadius: 8) + } else { + content + .frame(height: height) + .chartLegend(position: .bottom, alignment: .leading) + } } } @@ -117,7 +131,7 @@ struct BarChartView: View { var body: some View { let points = seriesPoints(props) let stacked = props.string("variant") == "stacked" - ChartFrame(props) { + ChartFrame(props, isEmpty: points.isEmpty) { Chart(points) { point in if stacked { BarMark(x: .value("Label", point.label), y: .value("Value", point.value)) @@ -134,6 +148,8 @@ struct BarChartView: View { .categoryAxisWithoutGrid() .chartXAxisLabel(props.text("xLabel")) .chartYAxisLabel(props.text("yLabel")) + .chartEntrance(.grow) + .openUIAnimation(Motion.dataMorph, value: points) } } } @@ -145,7 +161,7 @@ struct HorizontalBarChartView: View { let points = seriesPoints(props) let stacked = props.string("variant") == "stacked" let labels = labelOrder(props) - ChartFrame(props) { + ChartFrame(props, isEmpty: points.isEmpty) { Chart(points) { point in if stacked { BarMark( @@ -171,6 +187,8 @@ struct HorizontalBarChartView: View { .frame(minHeight: CGFloat(labels.count) * 28) .chartXAxisLabel(props.text("xLabel")) .chartYAxisLabel(props.text("yLabel")) + .chartEntrance(.growSideways) + .openUIAnimation(Motion.dataMorph, value: points) } } } @@ -180,8 +198,9 @@ struct LineChartView: View { var body: some View { let method = interpolation(props.string("variant")) - ChartFrame(props) { - Chart(seriesPoints(props)) { point in + let points = seriesPoints(props) + ChartFrame(props, isEmpty: points.isEmpty) { + Chart(points) { point in LineMark(x: .value("Label", point.label), y: .value("Value", point.value)) .foregroundStyle(by: .value("Series", point.series)) .interpolationMethod(method) @@ -190,6 +209,8 @@ struct LineChartView: View { .chartXScale(domain: labelOrder(props)) .paletteScale(seriesNames(props)) .categoryAxisWithoutGrid() + .chartEntrance(.draw) + .openUIAnimation(Motion.dataMorph, value: points) .chartXAxisLabel(props.text("xLabel")) .chartYAxisLabel(props.text("yLabel")) } @@ -203,8 +224,9 @@ struct AreaChartView: View { let method = interpolation(props.string("variant")) let names = seriesNames(props) let colors = ChartPalette.colors(names.count) - ChartFrame(props) { - Chart(seriesPoints(props)) { point in + let points = seriesPoints(props) + ChartFrame(props, isEmpty: points.isEmpty) { + Chart(points) { point in let color = colors[names.firstIndex(of: point.series) ?? 0] // react-ui fills areas with a gradient from 60% opacity to clear. AreaMark( @@ -224,6 +246,8 @@ struct AreaChartView: View { .chartXScale(domain: labelOrder(props)) .chartForegroundStyleScale(domain: names, range: colors) .categoryAxisWithoutGrid() + .chartEntrance(.draw) + .openUIAnimation(Motion.dataMorph, value: points) .chartXAxisLabel(props.text("xLabel")) .chartYAxisLabel(props.text("yLabel")) } @@ -231,7 +255,7 @@ struct AreaChartView: View { } /// One labelled value of a 1D chart. -private struct Slice: Identifiable { +private struct Slice: Identifiable, Equatable { let id: Int let label: String let value: Double @@ -276,6 +300,8 @@ struct PieChartView: View { .chartLegend(position: .bottom, alignment: .leading) .rotationEffect(semi ? .degrees(-90) : .zero) .frame(height: theme.chartHeight) + .openUIAnimation(Motion.dataMorph, value: data) + .fadeAppear() } } @@ -313,8 +339,9 @@ struct RadialChartView: View { } } } + .openUIAnimation(Motion.dataMorph, value: data) + .fadeAppear() } - } struct SingleStackedBarChartView: View { @@ -332,6 +359,8 @@ struct SingleStackedBarChartView: View { .chartYAxis(.hidden) .chartLegend(position: .bottom, alignment: .leading) .frame(height: 80) + .openUIAnimation(Motion.dataMorph, value: data) + .chartEntrance(.growSideways) } } @@ -369,6 +398,8 @@ struct ScatterChartView: View { .chartYAxisLabel(props.text("yLabel")) .chartLegend(position: .bottom, alignment: .leading) .frame(height: theme.chartHeight) + .openUIAnimation(Motion.dataMorph, value: dots.map(\.x) + dots.map(\.y)) + .fadeAppear() } /// react-ui's `calculateScatterDomain`: the data range padded by 10% on each @@ -438,6 +469,7 @@ struct RadarChartView: View { } } .frame(height: theme.chartHeight + 40) + .fadeAppear() FlowLayout(spacing: 12) { ForEach(Array(series.enumerated()), id: \.offset) { index, entry in HStack(spacing: 6) { diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift index 7cd4a6d45f..2124e1d0ad 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift @@ -301,9 +301,9 @@ struct RemoteImage: View { var body: some View { Group { if fit { - AsyncImage(url: url) { phase in + AsyncImage(url: url, transaction: Self.fadeIn) { phase in if let image = phase.image { - image.resizable().scaledToFit() + image.resizable().scaledToFit().transition(.opacity) } else { placeholder(phase).frame(height: 160) } @@ -312,9 +312,9 @@ struct RemoteImage: View { } else { Color.clear .overlay { - AsyncImage(url: url) { phase in + AsyncImage(url: url, transaction: Self.fadeIn) { phase in if let image = phase.image { - image.resizable().scaledToFill() + image.resizable().scaledToFill().transition(.opacity) } else { placeholder(phase) } @@ -329,11 +329,19 @@ struct RemoteImage: View { private var url: URL? { src.flatMap(URL.init(string:)) } + /// The photo fades in over its loading placeholder. + private static let fadeIn = Transaction(animation: .easeOut(duration: 0.25)) + + @ViewBuilder private func placeholder(_ phase: AsyncImagePhase) -> some View { - ZStack { - theme.sunkSurface - Image(systemName: phase.error == nil ? "photo" : "photo.badge.exclamationmark") - .font(.title2).foregroundStyle(.secondary) + if phase.error == nil, url != nil { + // Still loading: pulse like react-ui's skeletons. + GeometryReader { size in SkeletonBlock(height: size.size.height, cornerRadius: 0) } + } else { + ZStack { + theme.sunkSurface + Image(systemName: "photo.badge.exclamationmark").font(.title2).foregroundStyle(.secondary) + } } } } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift index bf77702630..0d4ca455e9 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift @@ -30,9 +30,7 @@ struct TableView: View { if context.isQueryLoading && rowCount == 0 { // Placeholder rows while a Query fills the table, like react-ui's skeleton. VStack(alignment: .leading, spacing: 10) { - ForEach(0..<5, id: \.self) { _ in - RoundedRectangle(cornerRadius: 4).fill(theme.sunkSurface).frame(height: 14) - } + ForEach(0..<5, id: \.self) { _ in SkeletonBlock(height: 14, cornerRadius: 4) } } } else if !columns.isEmpty { VStack(alignment: .leading, spacing: theme.compactSpacing) { @@ -331,7 +329,7 @@ struct TabsView: View { let isActive = value == active return Button { userChose = true - active = value + withOpenUIAnimation(Motion.reveal) { active = value } } label: { Text(item.text("trigger")) .font(.subheadline.weight(isActive ? .semibold : .regular)) @@ -350,7 +348,9 @@ struct TabsView: View { var candidate: String? for (value, size) in sizes where size > (contentSizes[value] ?? 0) { candidate = value } contentSizes = Dictionary(sizes.map { ($0.value, $0.size) }, uniquingKeysWith: { $1 }) - if let candidate { active = candidate } + if let candidate, candidate != active { + withOpenUIAnimation(Motion.reveal) { active = candidate } + } } } @@ -380,7 +380,7 @@ struct AccordionView: View { } .onChange(of: items.count, initial: true) { if !userChose, items.count > seenCount, let newest = items.last { - open = newest.text("value") + withOpenUIAnimation(Motion.reveal) { open = newest.text("value") } } seenCount = items.count } @@ -427,14 +427,16 @@ struct SectionBlockView: View { } .onChange(of: values.count, initial: true) { if context.isStreaming, values.count > seenCount, !userChose, let last = values.last { - open.insert(last) + withOpenUIAnimation(Motion.reveal) { _ = open.insert(last) } } else if open.isEmpty, let first = values.first { open = [first] } seenCount = values.count } .onChange(of: context.isStreaming) { wasStreaming, isStreaming in - if wasStreaming, !isStreaming, !userChose, let first = values.first { open = [first] } + if wasStreaming, !isStreaming, !userChose, let first = values.first { + withOpenUIAnimation(Motion.reveal) { open = [first] } + } } } } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Motion.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Motion.swift new file mode 100644 index 0000000000..0563d03ce1 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Motion.swift @@ -0,0 +1,130 @@ +import Charts +import SwiftUI + +/// The motion react-ui uses while a response streams in, so both renderers +/// feel the same. Everything here is skipped when Reduce Motion is on. +enum Motion { + /// react-ui's `dataMorph` spring (stiffness 480, damping 44): chart values + /// glide to their new positions as more data streams in. + static let dataMorph = Animation.interpolatingSpring(mass: 1, stiffness: 480, damping: 44) + + /// How a newly streamed part of the response appears. + static let insertion = Animation.easeOut(duration: 0.25) + + /// A tab, accordion or section changing what it shows. + static let reveal = Animation.easeInOut(duration: 0.2) +} + +extension AnyTransition { + /// Newly streamed nodes fade in and settle up a few points; removed ones fade out. + static var openUIInsertion: AnyTransition { + .asymmetric(insertion: .opacity.combined(with: .offset(y: 6)), removal: .opacity) + } +} + +extension View { + /// Animates changes to `value` unless Reduce Motion is on. + func openUIAnimation(_ animation: Animation, value: V) -> some View { + modifier(MotionAnimation(animation: animation, value: value)) + } +} + +private struct MotionAnimation: ViewModifier { + let animation: Animation + let value: V + @Environment(\.accessibilityReduceMotion) private var reduceMotion + + func body(content: Content) -> some View { + content.animation(reduceMotion ? nil : animation, value: value) + } +} + +/// Runs `change` with `animation`, or without one when Reduce Motion is on. +@MainActor +func withOpenUIAnimation(_ animation: Animation, _ change: () -> Void) { + #if canImport(UIKit) + let reduceMotion = UIAccessibility.isReduceMotionEnabled + #else + let reduceMotion = NSWorkspace.shared.accessibilityDisplayShouldReduceMotion + #endif + if reduceMotion { change() } else { withAnimation(animation, change) } +} + +/// A pulsing placeholder, like react-ui's skeleton bar: 30% to 85% opacity +/// and back every 1.2 seconds. +struct SkeletonBlock: View { + var height: CGFloat + var cornerRadius: CGFloat = 6 + @State private var bright = false + @Environment(\.accessibilityReduceMotion) private var reduceMotion + + var body: some View { + RoundedRectangle(cornerRadius: cornerRadius) + .fill(Color.primary.opacity(0.08)) + .frame(maxWidth: .infinity) + .frame(height: height) + .opacity(reduceMotion ? 0.6 : (bright ? 0.85 : 0.3)) + .onAppear { + guard !reduceMotion else { return } + withAnimation(.easeInOut(duration: 0.6).repeatForever(autoreverses: true)) { bright = true } + } + .accessibilityHidden(true) + } +} + +/// A chart's entrance, like react-ui's: bars grow up from the axis over 0.6s, +/// lines and areas draw from left to right over 1s. +struct ChartEntrance: ViewModifier { + enum Style { + case grow, growSideways, draw + } + + let style: Style + @State private var progress: CGFloat = 0 + @Environment(\.accessibilityReduceMotion) private var reduceMotion + + func body(content: Content) -> some View { + content + .chartPlotStyle { plot in + plot.mask { + Rectangle().scaleEffect( + x: style == .grow ? 1 : progress, y: style == .grow ? progress : 1, + anchor: style == .grow ? .bottom : .leading) + } + } + .onAppear { + guard progress == 0 else { return } + if reduceMotion { + progress = 1 + } else { + withAnimation(.easeOut(duration: style == .draw ? 1 : 0.6)) { progress = 1 } + } + } + } +} + +extension View { + func chartEntrance(_ style: ChartEntrance.Style) -> some View { + modifier(ChartEntrance(style: style)) + } +} + +/// react-ui's fade-appear entrance (0.6s) for charts that don't grow or draw: +/// pie, radial, radar and scatter. +private struct FadeAppear: ViewModifier { + @State private var visible = false + @Environment(\.accessibilityReduceMotion) private var reduceMotion + + func body(content: Content) -> some View { + content + .opacity(visible || reduceMotion ? 1 : 0) + .onAppear { + guard !visible else { return } + withAnimation(.easeOut(duration: 0.6)) { visible = true } + } + } +} + +extension View { + func fadeAppear() -> some View { modifier(FadeAppear()) } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUINode.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUINode.swift index a1e99d03aa..d15106eb8e 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUINode.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUINode.swift @@ -44,9 +44,11 @@ public struct OpenUINodes: View { public var body: some View { VStack(alignment: alignment, spacing: spacing) { ForEach(items) { item in - OpenUINode(item.value) + OpenUINode(item.value).transition(.openUIInsertion) } } + // Nodes keep their identity, so only newly streamed ones animate in. + .openUIAnimation(Motion.insertion, value: items.map(\.id)) } } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift index aa1c2c67c5..bd795e0445 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift @@ -62,6 +62,7 @@ public struct OpenUIRenderer: View { VStack(alignment: .leading, spacing: 0) { if let root = context.root { OpenUIElementView(element: root) + .transition(.openUIInsertion) .opacity(context.isQueryLoading ? 0.7 : 1) .animation(.easeInOut(duration: 0.2), value: context.isQueryLoading) .overlay(alignment: .topTrailing) { From 91fd9f7f5fea5883e470d7bf253de77062d7fb41 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:19:37 +0530 Subject: [PATCH 17/52] fix(swift-lang): show a finished response on the first frame The renderer parsed the response in onAppear/onChange, which run after the first layout. A finished response (a restored message, or one rebuilt when it scrolls back into view) laid out empty for a frame and then jumped, and a transcript scrolled to the end landed short of it. The context now preloads the response when it's created: it parses and seeds the store, but reports nothing and runs no queries, so callbacks and queries still start on the first update as before. The renderer keeps the context in a StateObject, whose initializer is an autoclosure, so the parse runs once per renderer and not on every init of the view. --- .../Sources/OpenUILang/Runtime.swift | 12 +++++++++ .../Sources/OpenUISwiftUI/OpenUIContext.swift | 5 +++- .../OpenUISwiftUI/OpenUIRenderer.swift | 25 ++++++++++++++++--- .../Tests/OpenUILangTests/RuntimeTests.swift | 25 +++++++++++++++++++ .../OpenUISwiftUITests/RendererTests.swift | 13 ++++++++++ 5 files changed, 75 insertions(+), 5 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUILang/Runtime.swift b/packages/swift-lang/Sources/OpenUILang/Runtime.swift index 358a800775..333b345671 100644 --- a/packages/swift-lang/Sources/OpenUILang/Runtime.swift +++ b/packages/swift-lang/Sources/OpenUILang/Runtime.swift @@ -74,6 +74,18 @@ public final class OpenUIRuntime { // MARK: Parsing + /// Parses `response` so it can be rendered right away, without telling the + /// host or starting queries. The next `update` reports it and starts them, + /// as if it were the first. + public func preload(response: String?, isStreaming: Bool) { + guard !hasParsed else { return } + self.isStreaming = isStreaming + self.response = response + guard let response, !response.isEmpty else { return } + parseResult = streamParser.set(response) + initializeStoreIfNeeded() + } + /// Feeds the latest full response text. Appended text parses incrementally. public func update(response: String?, isStreaming: Bool) { self.isStreaming = isStreaming diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift index 13f9abd27b..be5fc1d0db 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift @@ -38,9 +38,11 @@ public final class OpenUIContext { @ObservationIgnored var onError: (([OpenUIError]) -> Void)? @ObservationIgnored private var unsubscribers: [() -> Void] = [] + /// - Parameter response: The response to show on the first render, before + /// ``update(response:isStreaming:)`` is called. public init( library: SwiftUILibrary, initialState: OpenUIObject? = nil, - toolProvider: (any ToolProvider)? = nil + toolProvider: (any ToolProvider)? = nil, response: String? = nil, isStreaming: Bool = false ) { self.library = library self.runtime = OpenUIRuntime( @@ -51,6 +53,7 @@ public final class OpenUIContext { runtime.onError = { [weak self] errors in self?.onError?(errors) } unsubscribers.append(runtime.store.subscribe { [weak self] in self?.revision += 1 }) unsubscribers.append(runtime.queries.subscribe { [weak self] in self?.revision += 1 }) + runtime.preload(response: response, isStreaming: isStreaming) } /// Feeds the latest response text. diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift index bd795e0445..bfff14e30a 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift @@ -18,7 +18,12 @@ public struct OpenUIRenderer: View { let onParseResult: ((ParseResult?) -> Void)? let onError: (([OpenUIError]) -> Void)? - @State private var context: OpenUIContext + // A StateObject because its initializer is an autoclosure: the context (and + // the runtime behind it) is created once per view, not each time a parent + // redraws and builds this struct again. + @StateObject private var holder: ContextHolder + private var context: OpenUIContext { holder.context } + @Environment(\.openUITheme) private var theme /// - Parameters: /// - response: The response text so far. @@ -49,9 +54,14 @@ public struct OpenUIRenderer: View { self.onStateUpdate = onStateUpdate self.onParseResult = onParseResult self.onError = onError - _context = State( - initialValue: OpenUIContext( - library: library, initialState: initialState, toolProvider: toolProvider)) + // The context parses the response up front, so the first frame shows it. + // Without that, a renderer in a lazy stack is rebuilt empty each time it + // scrolls back into view, then grows, and the stack keeps re-placing rows. + _holder = StateObject( + wrappedValue: ContextHolder( + OpenUIContext( + library: library, initialState: initialState, toolProvider: toolProvider, + response: response, isStreaming: isStreaming))) } public var body: some View { @@ -115,3 +125,10 @@ public struct DefaultQueryLoader: View { ProgressView().controlSize(.small) } } + +/// Keeps a renderer's context for the life of the view. +@MainActor +private final class ContextHolder: ObservableObject { + let context: OpenUIContext + init(_ context: OpenUIContext) { self.context = context } +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/RuntimeTests.swift b/packages/swift-lang/Tests/OpenUILangTests/RuntimeTests.swift index 5de62d2754..d00bef74be 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/RuntimeTests.swift +++ b/packages/swift-lang/Tests/OpenUILangTests/RuntimeTests.swift @@ -30,6 +30,31 @@ struct FixtureLibrary: ComponentLibrary { .props["text"] == "n 3") } + /// `preload` renders a response before the host is told about it; the first + /// `update` with the same text reports it once, as if nothing came before. + @Test func preloadDefersCallbacksToTheFirstUpdate() { + let runtime = makeRuntime() + var reported = 0 + var stateUpdates = 0 + runtime.onParseResult = { _ in reported += 1 } + runtime.onStateUpdate = { _ in stateUpdates += 1 } + let response = "$count = 3\nroot = Card([Text(\"n \" + $count)])" + + runtime.preload(response: response, isStreaming: false) + #expect(reported == 0) + #expect(stateUpdates == 0) + #expect(runtime.store.get("$count") == 3) + #expect( + runtime.evaluatedRoot()?.props["children"]?.arrayValue?.first?.elementValue? + .props["text"] == "n 3") + + runtime.update(response: response, isStreaming: false) + #expect(reported == 1) + runtime.update(response: response, isStreaming: false) + #expect(reported == 1) + #expect(stateUpdates == 0) + } + @Test func keepsUserChangesWhenDeclarationsChange() { let runtime = makeRuntime() runtime.update(response: "$name = \"\"\nroot = Card([Text($name)])", isStreaming: true) diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index d13796e269..c97c6e710e 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -235,6 +235,19 @@ import Testing #expect(host.fittingSize.height > 400, "rendered \(host.fittingSize)") } + /// The response shows on the very first layout, before any onChange runs. + /// A renderer in a lazy stack is rebuilt each time it scrolls back into + /// view; if it came back empty and then grew, the stack would keep + /// re-placing rows. + @Test func rendersOnTheFirstFrame() { + let host = NSHostingView( + rootView: OpenUIRenderer( + response: Self.examples[1].input, library: OpenUIChatLibrary.library + ) + .frame(width: 420)) + #expect(host.fittingSize.height > 400, "first frame was \(host.fittingSize)") + } + @Test func passesParseResultsAndErrorsToTheHost() { final class Received { var parseResults = 0 From 9fd29d38df8f82b3476c128aefcd3fb3df5134ad Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:19:37 +0530 Subject: [PATCH 18/52] feat(swift-lang): take accent and chart colors from the theme OpenUITheme gets onAccent (react-ui's textAccentPrimary) and chartPalette (react-ui's defaultChartPalette). Primary and icon buttons, option rows, list actions, steps, icon badges and the editable table's save button use the theme's accent and onAccent instead of the app's accentColor, and the renderer tints controls with the accent. Charts pick from chartPalette the same way they pick from the default ramp; an empty palette falls back to the default. --- .../Components/CardComponents.swift | 4 +- .../Components/ChartComponents.swift | 50 +++++++++++++------ .../Components/FormComponents.swift | 14 +++++- .../Components/IconComponents.swift | 2 +- .../Components/LayoutComponents.swift | 7 +-- .../Components/SelectionComponents.swift | 2 +- .../OpenUISwiftUI/OpenUIRenderer.swift | 1 + .../Sources/OpenUISwiftUI/Theme.swift | 9 ++++ .../OpenUISwiftUITests/RendererTests.swift | 28 +++++++++++ 9 files changed, 92 insertions(+), 25 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift index 0770d73b6a..20c0b0fddc 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift @@ -676,8 +676,8 @@ private struct IconBadge: View { let color = statusColor(variant) return (color, color.opacity(0.14)) case "inverted": return (Color(white: 0.98), Color.primary) - case "filled": return (.white, .accentColor) - case "soft": return (.accentColor, Color.accentColor.opacity(0.14)) + case "filled": return (theme.onAccent, theme.accent) + case "soft": return (theme.accent, theme.accent.opacity(0.14)) default: return (.primary, theme.sunkSurface) } } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift index 809da96bce..859b151f8e 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift @@ -46,8 +46,9 @@ private func interpolation(_ variant: String?) -> InterpolationMethod { } } -/// react-ui's default chart palette (OCEAN_DEFAULT), with colors picked from -/// the middle of the ramp outwards like its `getDistributedColors`. +/// Chart colors picked like react-ui's `getDistributedColors`: from the middle +/// of the ramp outwards. The ramp is the theme's `chartPalette`, or react-ui's +/// default (OCEAN_DEFAULT) when the theme has none. enum ChartPalette { static let ocean: [Color] = [ 0x0D47A1, 0x1565C0, 0x1976D2, 0x1E88E5, 0x2196F3, 0x42A5F5, 0x64B5F6, 0x90CAF9, 0xBBDEFB, @@ -61,16 +62,18 @@ enum ChartPalette { return Color(red: red, green: green, blue: blue) } - static func colors(_ count: Int) -> [Color] { - let n = ocean.count + static func colors(_ count: Int, _ palette: [Color]? = nil) -> [Color] { + // An empty palette can't color anything, so it falls back like react-ui's. + let ramp = palette.flatMap { $0.isEmpty ? nil : $0 } ?? ocean + let n = ramp.count let mid = n / 2 switch count { case ...0: return [] - case 1: return [ocean[mid]] - case 2: return [ocean[max(mid - 1, 0)], ocean[min(mid + 1, n - 1)]] + case 1: return [ramp[mid]] + case 2: return [ramp[max(mid - 1, 0)], ramp[min(mid + 1, n - 1)]] default: let offset = (count - 1) / 2 - return (0.. [String] { return props.children("series").map { $0.text("category") }.filter { seen.insert($0).inserted } } +/// Colors chart series with the theme's palette. +private struct PaletteScale: ViewModifier { + let names: [String] + @Environment(\.openUITheme) private var theme + + func body(content: Content) -> some View { + content.chartForegroundStyleScale( + domain: names, range: ChartPalette.colors(names.count, theme.chartPalette)) + } +} + extension View { - /// Colors chart series with react-ui's palette. fileprivate func paletteScale(_ names: [String]) -> some View { - chartForegroundStyleScale(domain: names, range: ChartPalette.colors(names.count)) + modifier(PaletteScale(names: names)) } /// Horizontal grid lines only, as react-ui's cartesian charts draw them. @@ -219,11 +232,12 @@ struct LineChartView: View { struct AreaChartView: View { let props: ComponentProps + @Environment(\.openUITheme) private var theme var body: some View { let method = interpolation(props.string("variant")) let names = seriesNames(props) - let colors = ChartPalette.colors(names.count) + let colors = ChartPalette.colors(names.count, theme.chartPalette) let points = seriesPoints(props) ChartFrame(props, isEmpty: points.isEmpty) { Chart(points) { point in @@ -295,7 +309,7 @@ struct PieChartView: View { } } .chartForegroundStyleScale( - domain: data.map(\.label), range: ChartPalette.colors(data.count) + domain: data.map(\.label), range: ChartPalette.colors(data.count, theme.chartPalette) ) .chartLegend(position: .bottom, alignment: .leading) .rotationEffect(semi ? .degrees(-90) : .zero) @@ -311,7 +325,7 @@ struct RadialChartView: View { var body: some View { let data = slices(props) - let colors = ChartPalette.colors(props.array("values").count) + let colors = ChartPalette.colors(props.array("values").count, theme.chartPalette) let maximum = max(data.map(\.value).max() ?? 1, 1) HStack(spacing: theme.spacing) { ZStack { @@ -346,6 +360,7 @@ struct RadialChartView: View { struct SingleStackedBarChartView: View { let props: ComponentProps + @Environment(\.openUITheme) private var theme var body: some View { let data = slices(props) @@ -354,7 +369,7 @@ struct SingleStackedBarChartView: View { .foregroundStyle(by: .value("Label", slice.label)) } .chartForegroundStyleScale( - domain: data.map(\.label), range: ChartPalette.colors(data.count) + domain: data.map(\.label), range: ChartPalette.colors(data.count, theme.chartPalette) ) .chartYAxis(.hidden) .chartLegend(position: .bottom, alignment: .leading) @@ -393,7 +408,9 @@ struct ScatterChartView: View { } .chartXScale(domain: Self.domain(dots.map(\.x))) .chartYScale(domain: Self.domain(dots.map(\.y))) - .chartForegroundStyleScale(domain: names, range: ChartPalette.colors(names.count)) + .chartForegroundStyleScale( + domain: names, range: ChartPalette.colors(names.count, theme.chartPalette) + ) .chartXAxisLabel(props.text("xLabel")) .chartYAxisLabel(props.text("yLabel")) .chartLegend(position: .bottom, alignment: .leading) @@ -463,7 +480,7 @@ struct RadarChartView: View { $0 < entry.values.count ? entry.values[$0] / maximum : 0 } let shape = polygon(fractions) - let color = ChartPalette.colors(series.count)[index] + let color = ChartPalette.colors(series.count, theme.chartPalette)[index] context.fill(shape, with: .color(color.opacity(0.18))) context.stroke(shape, with: .color(color), lineWidth: 2) } @@ -473,7 +490,8 @@ struct RadarChartView: View { FlowLayout(spacing: 12) { ForEach(Array(series.enumerated()), id: \.offset) { index, entry in HStack(spacing: 6) { - Circle().fill(ChartPalette.colors(series.count)[index]).frame(width: 8, height: 8) + Circle().fill(ChartPalette.colors(series.count, theme.chartPalette)[index]).frame( + width: 8, height: 8) Text(entry.name).font(.caption).foregroundStyle(.secondary) } } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift index f82e1ab157..dbd28b0c45 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift @@ -337,10 +337,11 @@ private struct OptionRow: View { let symbol: String let label: String let description: String + @Environment(\.openUITheme) private var theme var body: some View { HStack(alignment: .firstTextBaseline, spacing: 8) { - Image(systemName: symbol).foregroundStyle(Color.accentColor) + Image(systemName: symbol).foregroundStyle(theme.accent) VStack(alignment: .leading, spacing: 2) { Text(label) if !description.isEmpty { @@ -556,11 +557,20 @@ private struct ButtonVariant: ViewModifier { switch variant { case "secondary": content.buttonStyle(.bordered) case "tertiary", "ghost": content.buttonStyle(.borderless) - default: content.buttonStyle(.borderedProminent) + default: content.modifier(ProminentButton()) } } } +/// A filled button in the theme's accent, with its `onAccent` label. +struct ProminentButton: ViewModifier { + @Environment(\.openUITheme) private var theme + + func body(content: Content) -> some View { + content.buttonStyle(.borderedProminent).foregroundStyle(theme.onAccent) + } +} + struct ButtonsView: View { let props: ComponentProps @Environment(\.openUITheme) private var theme diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift index 9b283bddc0..9d724b3eeb 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift @@ -374,7 +374,7 @@ private struct IconButtonStyle: ViewModifier { switch variant { case "secondary": content.buttonStyle(.bordered) case "tertiary": content.buttonStyle(.borderless) - default: content.buttonStyle(.borderedProminent) + default: content.modifier(ProminentButton()) } } if circle { diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift index 0d4ca455e9..49c0f4690e 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift @@ -177,7 +177,7 @@ private struct ListRow: View { Spacer(minLength: 0) if onTap != nil { if let actionLabel = item.string("actionLabel"), !actionLabel.isEmpty { - Text(actionLabel).font(.caption.weight(.medium)).foregroundStyle(Color.accentColor) + Text(actionLabel).font(.caption.weight(.medium)).foregroundStyle(theme.accent) } else { Image(systemName: "chevron.right").font(.caption).foregroundStyle(.secondary) } @@ -245,6 +245,7 @@ private struct FollowUpButton: View { struct StepsView: View { let props: ComponentProps + @Environment(\.openUITheme) private var theme var body: some View { let items = props.children("items") @@ -254,9 +255,9 @@ struct StepsView: View { VStack(spacing: 0) { Text("\(index + 1)") .font(.caption.weight(.bold).monospacedDigit()) - .foregroundStyle(.white) + .foregroundStyle(theme.onAccent) .frame(width: 22, height: 22) - .background(Color.accentColor, in: Circle()) + .background(theme.accent, in: Circle()) if index < items.count - 1 { Rectangle().fill(.secondary.opacity(0.3)).frame(width: 2).frame(maxHeight: .infinity) } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift index 94eabc5040..4ba4ed706b 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift @@ -256,7 +256,7 @@ struct EditableTableView: View { context.triggerAction("Save Changes", form: name) edits = [:] } - .buttonStyle(.borderedProminent) + .modifier(ProminentButton()) } } } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift index bfff14e30a..6d23c9d0eb 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift @@ -81,6 +81,7 @@ public struct OpenUIRenderer: View { } } .environment(context) + .tint(theme.accent) .onChange(of: response, initial: true) { context.update(response: response, isStreaming: isStreaming) } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift index c5fd347bc6..cba068fb34 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift @@ -11,7 +11,12 @@ public struct OpenUITheme: Sendable { public var cornerRadius: CGFloat = 10 public var smallCornerRadius: CGFloat = 6 public var cardPadding: CGFloat = 18 + /// Primary buttons, selected options, steps and other emphasis. The + /// renderer also tints its controls with it. public var accent: Color = .accentColor + /// Text and icons on accent backgrounds, like primary buttons (react-ui's + /// `textAccentPrimary`). Use a dark color with a light accent. + public var onAccent: Color = .white /// Raised surfaces such as clickable cards (react-ui's `foreground`). public var surface: Color = .platformElevatedBackground /// Recessed fills such as inputs (react-ui's `sunk`). @@ -22,6 +27,10 @@ public struct OpenUITheme: Sendable { /// Borders of clickable cards (react-ui's `border-interactive`). public var interactiveBorder: Color = .primary.opacity(0.12) public var chartHeight: CGFloat = 220 + /// Colors for chart series, like react-ui's `defaultChartPalette`: a ramp + /// that charts pick from the middle outwards. `nil` uses react-ui's default + /// blue ramp. + public var chartPalette: [Color]? public init() {} diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index c97c6e710e..6ca9330e5c 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -324,3 +324,31 @@ let globalTestLibrary = SwiftUILibrary( #expect(ScatterChartView.domain([]) == 0...100) } } + +/// Mirrors react-ui's paletteUtils tests. +@Suite struct ChartPaletteTests { + let ramp = ChartPalette.ocean + + @Test func picksFromTheMiddleOutwards() { + #expect(ChartPalette.colors(1) == [ramp[5]]) + #expect(ChartPalette.colors(2) == [ramp[4], ramp[6]]) + #expect(ChartPalette.colors(3) == [ramp[4], ramp[5], ramp[6]]) + #expect(ChartPalette.colors(5) == Array(ramp[3...7])) + } + + @Test func usesTheThemePaletteAndFallsBackWhenEmpty() { + let pastel: [Color] = [.pink, .mint, .yellow] + #expect(ChartPalette.colors(3, pastel) == pastel) + #expect(ChartPalette.colors(2, [.pink, .mint]) == [.pink, .mint]) + #expect(ChartPalette.colors(1, []) == [ramp[5]]) + } + + @Test func neverIndexesOutOfBounds() { + for size in 1...12 { + let palette = (0.. Date: Wed, 7 Oct 2026 13:19:37 +0530 Subject: [PATCH 19/52] feat(swift-lang): port react-ui's slider values and range slider The slider follows SliderBlock: the label row shows its values as number fields (a menu of steps for discrete sliders, up to 200), typed values get react-ui's messages ("Invalid number", "Value must be between X and Y", "Min must be less than max"), and two values make a two-thumb range slider that works with drag, VoiceOver and the arrow keys. --- .../Components/FormComponents.swift | 268 ++++++++++++++++-- .../OpenUISwiftUITests/RendererTests.swift | 20 ++ 2 files changed, 264 insertions(+), 24 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift index dbd28b0c45..76974d580d 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift @@ -436,6 +436,9 @@ struct DatePickerView: View { } } +/// A slider like react-ui's SliderBlock: the label with editable values (a +/// menu of steps when discrete), then the track. Two values make it a range +/// with a thumb at each end. struct SliderView: View { let props: ComponentProps @Environment(OpenUIContext.self) private var context @@ -446,35 +449,46 @@ struct SliderView: View { let state = FieldContext(props, context: context, form: form) let minimum = props.number("min") ?? 0 let maximum = max(props.number("max") ?? 100, minimum) - let step = props.string("variant") == "discrete" ? max(props.number("step") ?? 1, 0.0001) : nil + let discrete = props.string("variant") == "discrete" + // react-ui steps a continuous slider by at least 1. + let step = discrete ? max(props.number("step") ?? 1, 0.0001) : max(1, props.number("step") ?? 1) let stored = state.field.value.isNullish ? props["defaultValue"] : state.field.value let values = (stored.arrayValue ?? []).compactMap(\.numberValue) - let current = values.isEmpty ? [minimum] : values - VStack(alignment: .leading, spacing: 4) { - HStack { - Text(props.string("label") ?? state.field.name).font(.subheadline) - Spacer() - Text(current.map(jsNumberToString).joined(separator: " – ")) - .font(.subheadline.monospacedDigit()).foregroundStyle(.secondary) + let current = values.isEmpty ? [minimum] : Array(values.prefix(2)) + let errors = discrete ? [] : Self.errors(current, minimum: minimum, maximum: maximum) + let set: @MainActor ([Double]) -> Void = { next in + state.field.setValue(.array(next.map { .number($0) })) + if !state.rules.isEmpty { + validation?.validateField(state.field.name, value: .number(next[0]), rules: state.rules) } - ForEach(current.indices, id: \.self) { index in - let binding = Binding( - get: { min(max(current[index], minimum), maximum) }, - set: { newValue in - var next = current - next[index] = newValue - state.field.setValue(.array(next.map { .number($0) })) - if !state.rules.isEmpty { - validation?.validateField( - state.field.name, value: .number(next[0]), rules: state.rules) - } - }) - if let step { - Slider(value: binding, in: minimum...maximum, step: step) - } else { - Slider(value: binding, in: minimum...maximum) + } + VStack(alignment: .leading, spacing: 6) { + HStack(spacing: 8) { + Text(props.string("label") ?? state.field.name).font(.subheadline) + Spacer(minLength: 8) + // Step-derived controls wait until the props stop streaming. + if !context.isStreaming { + SliderValueControls( + values: current, minimum: minimum, maximum: maximum, step: step, discrete: discrete, + errors: errors, onChange: set) } } + if !context.isStreaming, let error = errors.first(where: { !$0.isEmpty }) { + Label(error, systemImage: "exclamationmark.circle") + .font(.caption).foregroundStyle(.red) + } + if current.count > 1 { + RangeSlider( + lower: min(current[0], current[1]), upper: max(current[0], current[1]), + bounds: minimum...maximum, step: step + ) { set([$0, $1]) } + } else { + Slider( + value: Binding( + get: { min(max(current[0], minimum), maximum) }, + set: { set([$0]) }), + in: minimum...maximum, step: step) + } HStack { Text(compactNumber(minimum)) Spacer() @@ -486,6 +500,212 @@ struct SliderView: View { .disabled(context.isStreaming) .formField(state.field.name, rules: state.rules, value: state.field.value) } + + /// react-ui's messages for typed values: one per value, empty when fine. + static func errors(_ values: [Double], minimum: Double, maximum: Double) -> [String] { + var errors = values.map { value -> String in + if value.isNaN { return "Invalid number" } + if value < minimum || value > maximum { + return "Value must be between \(jsNumberToString(minimum)) and \(jsNumberToString(maximum))" + } + return "" + } + if values.count > 1, values[0] > values[1] { errors[0] = "Min must be less than max" } + return errors + } +} + +/// The values beside a slider's label: number fields, or menus of the steps +/// when the slider is discrete. +private struct SliderValueControls: View { + let values: [Double] + let minimum: Double + let maximum: Double + let step: Double + let discrete: Bool + let errors: [String] + let onChange: @MainActor ([Double]) -> Void + + /// Above this many steps a menu is unwieldy, so discrete sliders get a + /// number field instead. + private static let maximumMenuOptions = 200 + + var body: some View { + let options = discrete ? Self.options(minimum, maximum, step) : [] + let useMenus = discrete && options.count <= Self.maximumMenuOptions + HStack(spacing: 6) { + if values.count > 1 { + let lower = values[0] + let upper = values[1] + if useMenus { + menu(lower, options.filter { $0 < upper }) { onChange([$0, upper].sorted()) } + separator + menu(upper, options.filter { $0 > lower }) { onChange([lower, $0].sorted()) } + } else { + SliderValueField(value: lower, hasError: !errors[0].isEmpty) { onChange([$0, upper]) } + separator + SliderValueField(value: upper, hasError: !(errors.last ?? "").isEmpty) { + onChange([lower, $0]) + } + } + } else if useMenus { + menu(values[0], options) { onChange([$0]) } + } else { + SliderValueField(value: values[0], hasError: !(errors.first ?? "").isEmpty) { + onChange([$0]) + } + } + } + } + + private var separator: some View { + Rectangle().fill(Color.secondary.opacity(0.5)).frame(width: 8, height: 1) + } + + private func menu( + _ value: Double, _ options: [Double], _ select: @escaping @MainActor (Double) -> Void + ) + -> some View + { + Picker( + "Value", + selection: Binding(get: { value }, set: { select($0) }) + ) { + ForEach(options, id: \.self) { Text(jsNumberToString($0)).tag($0) } + } + .labelsHidden() + .pickerStyle(.menu) + .fixedSize() + } + + /// Every step from `minimum` to `maximum`, like react-ui's option list. + static func options(_ minimum: Double, _ maximum: Double, _ step: Double) -> [Double] { + let count = Int(((maximum - minimum) / step).rounded(.down)) + 1 + guard count > 0 else { return [] } + return (0.. Void + @State private var text = "" + @FocusState private var focused: Bool + + var body: some View { + TextField("Value", text: $text) + .labelsHidden() + .multilineTextAlignment(.center) + .font(.subheadline.monospacedDigit()) + .frame(width: 64) + .padding(.vertical, 4) + .background(Color.primary.opacity(0.05), in: RoundedRectangle(cornerRadius: 6)) + .overlay( + RoundedRectangle(cornerRadius: 6) + .strokeBorder(hasError ? Color.red : Color.primary.opacity(0.1)) + ) + .focused($focused) + #if os(iOS) + .keyboardType(.numbersAndPunctuation) + #endif + .onAppear { text = jsNumberToString(value) } + .onChange(of: value) { if !focused { text = jsNumberToString(value) } } + .onChange(of: focused) { if !focused { text = jsNumberToString(value) } } + .onChange(of: text) { + let number = jsStringToNumber(text) + if !number.isNaN, focused { onChange(number) } + } + } +} + +/// One track with a thumb at each end of a range, like react-ui's range +/// slider. A thumb stops at the other one rather than crossing it. +struct RangeSlider: View { + let lower: Double + let upper: Double + let bounds: ClosedRange + let step: Double + let onChange: @MainActor (Double, Double) -> Void + @Environment(\.isEnabled) private var isEnabled + private let thumbSize: CGFloat = 24 + + var body: some View { + GeometryReader { geometry in + let track = max(geometry.size.width - thumbSize, 1) + ZStack(alignment: .leading) { + Capsule() + .fill(Color.primary.opacity(0.12)) + .frame(height: 4) + .padding(.horizontal, thumbSize / 2) + Capsule() + .fill(.tint) + .frame(width: max(0, offset(upper, track) - offset(lower, track)), height: 4) + .offset(x: offset(lower, track) + thumbSize / 2) + thumb(isLower: true, value: lower, track: track) + thumb(isLower: false, value: upper, track: track) + } + .frame(maxHeight: .infinity) + } + .frame(height: thumbSize + 4) + .opacity(isEnabled ? 1 : 0.5) + } + + private func offset(_ value: Double, _ track: CGFloat) -> CGFloat { + let span = bounds.upperBound - bounds.lowerBound + return span > 0 ? CGFloat((value - bounds.lowerBound) / span) * track : 0 + } + + private func thumb(isLower: Bool, value: Double, track: CGFloat) -> some View { + Circle() + .fill(.white) + .shadow(color: .black.opacity(0.2), radius: 2, y: 1) + .overlay(Circle().strokeBorder(Color.black.opacity(0.06))) + .frame(width: thumbSize, height: thumbSize) + .offset(x: offset(value, track)) + .gesture( + DragGesture(minimumDistance: 0) + .onChanged { drag in + let span = bounds.upperBound - bounds.lowerBound + let position = offset(value, track) + drag.translation.width + move(isLower: isLower, to: bounds.lowerBound + Double(position / track) * span) + } + ) + .accessibilityElement() + .accessibilityLabel(isLower ? "Minimum" : "Maximum") + .accessibilityValue(jsNumberToString(value)) + .accessibilityAdjustableAction { direction in + let delta = direction == .increment ? step : -step + move(isLower: isLower, to: value + delta) + } + .focusable() + .onKeyPress(.leftArrow) { + move(isLower: isLower, to: value - step) + return .handled + } + .onKeyPress(.rightArrow) { + move(isLower: isLower, to: value + step) + return .handled + } + } + + private func move(isLower: Bool, to value: Double) { + let snapped = Self.snap(value, bounds: bounds, step: step) + if isLower { + onChange(min(snapped, upper), upper) + } else { + onChange(lower, max(snapped, lower)) + } + } + + /// The nearest step to `value`, within `bounds`. + static func snap(_ value: Double, bounds: ClosedRange, step: Double) -> Double { + guard step > 0 else { return min(max(value, bounds.lowerBound), bounds.upperBound) } + let steps = ((value - bounds.lowerBound) / step).rounded() + return min(max(bounds.lowerBound + steps * step, bounds.lowerBound), bounds.upperBound) + } } // MARK: - Buttons diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 6ca9330e5c..2814eff563 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -352,3 +352,23 @@ let globalTestLibrary = SwiftUILibrary( } } } + +/// The slider's range logic, against react-ui's SliderBlock. +@MainActor +@Suite struct SliderTests { + @Test func snapsToStepsWithinBounds() { + #expect(RangeSlider.snap(23, bounds: 0...100, step: 5) == 25) + #expect(RangeSlider.snap(-7, bounds: 0...100, step: 5) == 0) + #expect(RangeSlider.snap(140, bounds: 0...100, step: 5) == 100) + #expect(RangeSlider.snap(12.4, bounds: 10...20, step: 0.5) == 12.5) + } + + @Test func reportsReactUIErrors() { + #expect(SliderView.errors([20, 80], minimum: 0, maximum: 100) == ["", ""]) + #expect( + SliderView.errors([120], minimum: 0, maximum: 100) == ["Value must be between 0 and 100"]) + #expect( + SliderView.errors([90, 10], minimum: 0, maximum: 100) == ["Min must be less than max", ""]) + #expect(SliderView.errors([.nan], minimum: 0, maximum: 100) == ["Invalid number"]) + } +} From 8f2a772c34332fdaac5a26affc4186d71a631f89 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:19:38 +0530 Subject: [PATCH 20/52] feat(swift-lang): snap carousels and fade their edges like react-ui Carousel and the carousel card blocks share one scroller: items snap to the leading edge, an edge fades out while there's more to scroll that way (40pt, 48pt for card blocks), and Carousel gets react-ui's step buttons. Card widths come from containerRelativeFrame instead of a measured width, so the first frame no longer lays out at the wrong width and jumps. The fades and buttons read the scroll geometry but never change the layout. --- .../Components/CardComponents.swift | 20 ++-- .../Components/LayoutComponents.swift | 106 ++++++++++++++++-- 2 files changed, 105 insertions(+), 21 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift index 20c0b0fddc..dd38cbff4f 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift @@ -174,7 +174,6 @@ private struct CardBlockLayout: View { let maxPerRow: Int let click: (Int, ComponentProps) -> (label: String, context: OpenUIObject) @ViewBuilder let item: (ComponentProps) -> Item - @State private var width: CGFloat = 0 @Environment(OpenUIContext.self) private var context @Environment(\.openUIFormName) private var form @@ -184,14 +183,14 @@ private struct CardBlockLayout: View { let clickable = props["action"].isTruthy && !context.isStreaming Group { if props.string("layout") == "carousel" { - let cardWidth: CGFloat = size == .small || width <= 480 ? 280 : 320 - ScrollView(.horizontal, showsIndicators: false) { - HStack(alignment: .top, spacing: gap) { - ForEach(items.indices, id: \.self) { index in - card(index, items[index], clickable: clickable).frame(width: cardWidth) + CarouselScroller(count: items.count, spacing: gap, fade: 48, verticalPadding: 4) { index in + card(index, items[index], clickable: clickable) + // Sized from the visible width in the same layout pass: measuring + // it into state instead lays the cards out at the wrong width for a + // frame, then changes their height. + .containerRelativeFrame(.horizontal) { width, _ in + size == .small || width <= 480 ? 280 : 320 } - } - .padding(.vertical, 4) } } else { ResponsiveCardGrid( @@ -203,11 +202,6 @@ private struct CardBlockLayout: View { } } .frame(maxWidth: .infinity, alignment: .leading) - .onGeometryChange(for: CGFloat.self) { - $0.size.width - } action: { - width = $0 - } } @ViewBuilder diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift index 49c0f4690e..eb9b057ab6 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift @@ -477,21 +477,111 @@ private struct Disclosure: View { // MARK: - Carousel -/// Slides scroll horizontally; each slide is an array of content. +/// Slides scroll horizontally, like react-ui's Carousel: 280-point cards +/// (248 on narrow screens) with buttons to step through them. struct CarouselView: View { let props: ComponentProps @Environment(\.openUITheme) private var theme var body: some View { + let slides = props.array("children") + let fill = props.string("variant") == "sunk" ? theme.subtleSurface : theme.surface + CarouselScroller( + count: slides.count, spacing: 12, fade: 40, showsButtons: true, equalHeights: true + ) { + index in + OpenUINodes(slides[index].arrayValue ?? [slides[index]]) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + .padding(12) + .background(fill, in: RoundedRectangle(cornerRadius: 14)) + .overlay(RoundedRectangle(cornerRadius: 14).strokeBorder(theme.border)) + .containerRelativeFrame(.horizontal) { width, _ in width <= 400 ? 248 : 280 } + } + } +} + +/// A horizontal row that scrolls like react-ui's carousels: items snap to the +/// leading edge, an edge fades out where there's more to scroll, and optional +/// buttons step one item at a time. Whether it can scroll only drives the +/// fades and buttons, never a size, so it can't feed back into layout. +struct CarouselScroller: View { + let count: Int + var spacing: CGFloat + /// How far an edge fades out: 40 for react-ui's Carousel, its `space-3xl` + /// (48) for card blocks. + var fade: CGFloat + var showsButtons = false + /// Stretches items to the tallest one, as a flex row does. + var equalHeights = false + var verticalPadding: CGFloat = 2 + @ViewBuilder let item: (Int) -> Item + @State private var position: Int? + @State private var content = CGRect.zero + @State private var visibleWidth: CGFloat = 0 + @Environment(\.openUITheme) private var theme + + var body: some View { + let canScrollBack = content.minX < -1 + let canScrollOn = content.maxX > visibleWidth + 1 ScrollView(.horizontal, showsIndicators: false) { - HStack(alignment: .top, spacing: theme.spacing) { - ForEach(Array(props.array("children").enumerated()), id: \.offset) { _, slide in - OpenUINodes(slide.arrayValue ?? [slide]) - .frame(width: 260, alignment: .topLeading) - .surface(props.string("variant") ?? "card") - } + HStack(alignment: .top, spacing: spacing) { + ForEach(0.. some View { + Button { + withOpenUIAnimation(Motion.reveal) { + position = min(max((position ?? 0) + step, 0), count - 1) + } + } label: { + Image(systemName: step < 0 ? "chevron.left" : "chevron.right") + .font(.footnote.weight(.semibold)) + .frame(width: 28, height: 28) + .background(theme.surface, in: RoundedRectangle(cornerRadius: theme.smallCornerRadius)) + .overlay( + RoundedRectangle(cornerRadius: theme.smallCornerRadius).strokeBorder( + theme.interactiveBorder) + ) + .shadow(color: .black.opacity(0.08), radius: 3, y: 1) + } + .buttonStyle(.plain) + .accessibilityLabel(step < 0 ? "Previous" : "Next") + .offset(x: step < 0 ? -12 : 12) } } From 5062f8d5ce4e72909254af24147a4af225b491c7 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:19:38 +0530 Subject: [PATCH 21/52] feat(swift-lang): port OpenUI Cloud's message helpers Ports react-ui's sentinelParser and the message builders its GenUIAssistantMessage uses: split a stored message into the program and its context, wrap content and context, build the follow-up and form state messages react-ui sends, restore form state from a message, and read ]]>openui:artifact headers. Offsets are UTF-16, as in JavaScript. generate-fixtures.mjs imports sentinelParser.ts directly (Node strips the types) and writes messages.json, which the new tests check the port against. --- .../swift-lang/Scripts/generate-fixtures.mjs | 86 +++- .../Sources/OpenUILang/CloudMessages.swift | 306 ++++++++++++++ .../Sources/OpenUILang/JSSemantics.swift | 2 +- .../OpenUILangTests/EditAndCloudTests.swift | 89 +++++ .../OpenUILangTests/Fixtures/messages.json | 374 ++++++++++++++++++ 5 files changed, 855 insertions(+), 2 deletions(-) create mode 100644 packages/swift-lang/Sources/OpenUILang/CloudMessages.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/Fixtures/messages.json diff --git a/packages/swift-lang/Scripts/generate-fixtures.mjs b/packages/swift-lang/Scripts/generate-fixtures.mjs index b186e8f377..08ec467fc6 100644 --- a/packages/swift-lang/Scripts/generate-fixtures.mjs +++ b/packages/swift-lang/Scripts/generate-fixtures.mjs @@ -639,6 +639,89 @@ const chatCloud = { sha256: createHash("sha256").update(chatCloudConfig).digest("hex"), }; +// ── Cloud messages ──────────────────────────────────────────────────────── + +// react-ui doesn't export its sentinel parser, so read the source directly +// (Node strips the TypeScript types). +const sentinel = await import(join(packages, "react-ui", "src", "utils", "sentinelParser.ts")); + +const messageInputs = [ + ["empty", ""], + ["plain text", "Just some text"], + ["content only", "]]>openui:content\nroot = Card([])"], + ["content with header attrs", "]]>openui:content?thesys=true&libraryVersion=0.1.0\nroot = Card([])"], + ["content and context", ']]>openui:content\nroot = Card([])\n]]>openui:context\n[{"f":1}]'], + ["context only", 'Hello\n]]>openui:context\n["User clicked: Go"]'], + ["context then content", ']]>openui:context\n[1]\n]]>openui:content\nroot = X()'], + ["last content wins", "]]>openui:content\nold\n]]>openui:content\nnew"], + ["crlf separators", "]]>openui:content\r\nroot = X()\r\n]]>openui:context\r\n[1]"], + ["end marker", "]]>openui:content\nroot = X()\n]]>openui:end"], + ["end marker with attrs", "]]>openui:content\nroot = X()\n]]>openui:end?status=done"], + ["text after end marker", "]]>openui:content\nroot = X()\n]]>openui:end\ntrailing"], + ["end between sections", "]]>openui:content\na\n]]>openui:end\n]]>openui:context\n[1]"], + ["two end markers", "]]>openui:content\na\n]]>openui:end\n]]>openui:end"], + ["crlf before end", "]]>openui:content\na\r\n]]>openui:end"], + ["partial tail one char", "]]>openui:content\nroot = X()\n]"], + ["partial tail sentinel", "]]>openui:content\nroot = X()\n]]>openui:"], + ["partial context marker", "]]>openui:content\nroot = X()\n]]>openui:cont"], + ["partial end marker", "]]>openui:content\nroot = X()\n]]>openui:e"], + ["bracket that isn't a marker", "]]>openui:content\nx = [1, 2]"], + ["marker header without newline", "]]>openui:content"], + ["markers on one line", "]]>openui:content]]>openui:context\n[1]"], + ["emoji", "]]>openui:content\nroot = TextContent(\"🙂 hi\")\n]]>openui:context\n[\"🎉\"]"], + ["legacy xml", 'root = X()\n[{"a":1}]'], + ["legacy content only", "root = X() "], + ["legacy context only", 'text\n["x"]\n'], + ["legacy unclosed", "root = X()"], + ["legacy text after context", "[1] more"], +]; + +const langSyntaxInputs = [ + "```openui-lang\nroot = X()\n```", + "root = X()", + "root=X()", + " root = X()", + "intro\n\troot = X()", + "intro\n\n root\n= X()", + "rooted = 1", + "x root = 1", + "Just text", + "", +]; + +const artifactInputs = [ + ']]>openui:artifact {"artifact_id":"a1","type":"slides","name":"Deck","version":"2"}\nroot = X()', + ']]>openui:artifact {"artifact_id":"a2","type":"presentation"}\nprogram', + ']]>openui:artifact {"artifact_id":"a3","type":"report","name":""}', + ']]>openui:artifact {"artifact_id":"","type":"report"}\nx', + ']]>openui:artifact {"type":"report"}\nx', + ']]>openui:artifact {"artifact_id":"a4","type":"video"}\nx', + ']]>openui:artifact {"artifact_id":"a5","type":"report","version":7}\nx', + "]]>openui:artifact not json\nx", + "]]>openui:artifact []\nx", + ']]>openui:artifact{"artifact_id":"a6","type":"report"}\nx', + "]]>openui:content\nroot = X()", +]; + +const messageCases = { + separate: messageInputs.map(([name, input]) => ({ + name, + input, + expected: sentinel.separateContentAndContext(input), + })), + langSyntax: langSyntaxInputs.map((input) => ({ input, expected: sentinel.hasLangSyntax(input) })), + artifacts: artifactInputs.map((input) => ({ + input, + expected: sentinel.parseArtifactSentinel(input), + })), + wrap: { + content: sentinel.wrapContent("root = X()"), + contentWithHeader: sentinel.wrapContentWithHeader("root = X()", "]]>openui:content?thesys=true"), + contentWithoutHeader: sentinel.wrapContentWithHeader("root = X()", undefined), + context: sentinel.wrapContext('[{"a":1}]'), + }, +}; + function write(name, data, indent = 1) { mkdirSync(fixtures, { recursive: true }); writeFileSync(join(fixtures, name), JSON.stringify(data, null, indent) + "\n"); @@ -653,6 +736,7 @@ write("prompts.json", promptCases); write("merge.json", mergeCases); write("errors.json", errorCases); write("cloud.json", { cases: cloudCases, chat: chatCloud }); +write("messages.json", messageCases); // The chat examples, for the SwiftUI renderer's end-to-end render tests. mkdirSync(join(here, "..", "Tests", "OpenUISwiftUITests", "Fixtures"), { recursive: true }); @@ -667,5 +751,5 @@ writeFileSync( write("chat-spec.json", chatComponentSpecs); console.log( - `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set, ${evalFixtures.length} evaluation, ${promptCases.length} prompt, ${mergeCases.length} merge, ${errorCases.length} error, ${cloudCases.length} cloud fixtures`, + `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set, ${evalFixtures.length} evaluation, ${promptCases.length} prompt, ${mergeCases.length} merge, ${errorCases.length} error, ${cloudCases.length} cloud, ${messageCases.separate.length} message fixtures`, ); diff --git a/packages/swift-lang/Sources/OpenUILang/CloudMessages.swift b/packages/swift-lang/Sources/OpenUILang/CloudMessages.swift new file mode 100644 index 0000000000..98f382e53f --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/CloudMessages.swift @@ -0,0 +1,306 @@ +/// OpenUI Cloud's inline message format: the markers that separate a message's +/// openui-lang content from the context it carries (form state, what the user +/// clicked). Port of react-ui's `utils/sentinelParser.ts`, plus the messages +/// react-ui's `GenUIAssistantMessage` builds with it. +/// +/// Like the JavaScript, this works on UTF-16 code units, so `\r\n` is two +/// units rather than one Swift `Character`. + +private let inlineSentinel = "]]>openui:" +private let contentMarker = Array("\(inlineSentinel)content".utf16) +private let contextMarker = Array("\(inlineSentinel)context".utf16) +private let endMarker = Array("\(inlineSentinel)end".utf16) +private let artifactPrefix = Array("\(inlineSentinel)artifact ".utf16) + +/// Tokens whose partial prefix can sit at the tail of a still-streaming chunk. +/// Trimming keeps a half-arrived marker from flashing as raw text; the next +/// delta re-parses the whole message, so a false positive is transient. +private let streamPartialTokens = [contentMarker, contextMarker, endMarker] + +private let newline = UInt16(ascii: "\n") +private let carriageReturn = UInt16(ascii: "\r") + +/// A message split into its sections. +public struct ParsedMessageContent: Sendable, Equatable { + /// The openui-lang program (or plain text) to render. + public var content: String + /// The context section's JSON, if there is one. + public var contextString: String? + /// The content marker line, attributes included, so it can be written back + /// unchanged when the message is saved again. + public var contentHeader: String? + /// Whether the `]]>openui:end` marker was present: the stream reached its + /// last chunk. A saved message without it was cut off mid-stream. + public var end: Bool + + public init( + content: String, contextString: String? = nil, contentHeader: String? = nil, end: Bool = false + ) { + self.content = content + self.contextString = contextString + self.contentHeader = contentHeader + self.end = end + } +} + +/// `text` as a content section. +public func wrapContent(_ text: String) -> String { + "\(inlineSentinel)content\n\(text)" +} + +/// `text` as a content section under its original header line, so the +/// header's attributes survive saving form state into the message. +public func wrapContentWithHeader(_ text: String, _ contentHeader: String?) -> String { + if let contentHeader, !contentHeader.isEmpty { return "\(contentHeader)\n\(text)" } + return wrapContent(text) +} + +/// `json` as a context section, to append after the content. +public func wrapContext(_ json: String) -> String { + "\n\(inlineSentinel)context\n\(json)" +} + +/// Separates a message's content from its context, dropping what is only +/// noise for display: the end marker and a marker cut off at the end of a +/// streaming chunk. +public func separateContentAndContext(_ raw: String) -> ParsedMessageContent { + let (text, end) = extractEndMarker(Array(raw.utf16)) + let sections = splitSections(text) + return ParsedMessageContent( + content: string(stripStreamingTail(sections.content)), + contextString: sections.context.map(string), + contentHeader: sections.header.map(string), end: end) +} + +/// Whether the content holds openui-lang: the ```` ```openui-lang ```` fence, +/// or an unfenced top-level `root =` statement. +public func hasLangSyntax(_ content: String?) -> Bool { + guard let content, !content.isEmpty else { return false } + if content.contains("```openui-lang") { return true } + // /(^|\n)\s*root\s*=/ + let units = Array(content.utf16) + let root = Array("root".utf16) + for start in units.indices where start == 0 || units[start - 1] == newline { + var index = skipWhitespace(units, from: start) + guard units[index...].starts(with: root) else { continue } + index = skipWhitespace(units, from: index + root.count) + if index < units.count, units[index] == UInt16(ascii: "=") { return true } + } + return false +} + +// MARK: Messages react-ui's chat builds + +/// The user message react-ui's chat sends for a `continue_conversation` +/// action: the action's text as content, and as context what the user clicked +/// plus the form's values. +public func continueConversationMessage(_ event: ActionEvent) -> String { + let content = event.humanFriendlyMessage.isEmpty ? "" : wrapContent(event.humanFriendlyMessage) + var context: [OpenUIValue] = [.string("User clicked: \(event.humanFriendlyMessage)")] + if let formState = event.formState { context.append(.object(formState)) } + return content + wrapContext(JSON.stringify(.array(context))) +} + +/// An assistant message with the state its UI holds (form values, `$state`), +/// for saving with the conversation. Pass the parsed content and header; with +/// no state, the message is just the content. +public func messageWithState(content: String, contentHeader: String?, state: OpenUIObject) + -> String +{ + let message = wrapContentWithHeader(content, contentHeader) + guard !state.isEmpty else { return message } + return message + wrapContext(JSON.stringify(.array([.object(state)]))) +} + +/// The state saved in a message's context (see ``messageWithState``), for the +/// renderer's `initialState`. +public func initialState(fromContext contextString: String?) -> OpenUIObject? { + guard let contextString, let parsed = try? JSON.parse(contextString) else { return nil } + switch parsed { + case .array(let items): return items.first?.objectValue + case .object(let object): return object + default: return nil + } +} + +// MARK: Artifacts + +/// The kinds of artifact Cloud produces. +public enum ArtifactKind: String, Sendable, Equatable { + case slides + case report +} + +/// An artifact's header: which artifact, and what kind. +public struct ArtifactSentinelHeader: Sendable, Equatable { + public var artifactId: String + public var type: ArtifactKind + public var name: String? + public var version: String? +} + +/// Parses the artifact carrier `]]>openui:artifact \n`, +/// which arrives as a tool result. The program is empty on a reload that +/// stripped it. Returns `nil` for anything that isn't a valid carrier. +public func parseArtifactSentinel(_ raw: String) -> ( + header: ArtifactSentinelHeader, program: String +)? { + let units = Array(raw.utf16) + guard units.starts(with: artifactPrefix) else { return nil } + let newlineIndex = units.firstIndex(of: newline) + let header = string(units[artifactPrefix.count..<(newlineIndex ?? units.count)]) + let program = newlineIndex.map { string(units[($0 + 1)...]) } ?? "" + guard let fields = (try? JSON.parse(header))?.objectValue, + let id = fields["artifact_id"]?.stringValue, !id.isEmpty, + let type = fields["type"]?.stringValue.flatMap(artifactKind) + else { return nil } + let name = fields["name"]?.stringValue.flatMap { $0.isEmpty ? nil : $0 } + let version = fields["version"]?.stringValue.flatMap { $0.isEmpty ? nil : $0 } + return (ArtifactSentinelHeader(artifactId: id, type: type, name: name, version: version), program) +} + +private func artifactKind(_ type: String) -> ArtifactKind? { + switch type { + case "slides", "presentation": return .slides + case "report": return .report + default: return nil + } +} + +// MARK: - Sections + +private typealias Units = ArraySlice + +private func string(_ units: Units) -> String { String(decoding: units, as: UTF16.self) } + +/// The ordered walk over the inline-sentinel sections. +private func splitSections(_ raw: Units) -> (content: Units, context: Units?, header: Units?) { + let lastContent = lastIndex(of: contentMarker, in: raw) + let lastContext = lastIndex(of: contextMarker, in: raw) + + // No inline markers: fall back to the old XML envelope, so messages saved + // by older app versions still load. + guard lastContent != nil || lastContext != nil else { + let legacy = parseLegacyXML(raw) + return (legacy.content, legacy.context, nil) + } + guard let content = lastContent else { + return (stripSectionSeparator(raw[.. content else { + return (raw[bodyStart(raw, content)...], nil, header) + } + let body = raw[min(bodyStart(raw, content), context)..openui:end` marker line and reports whether there was +/// one. The newline before the marker goes with it, attributes on the marker +/// line are ignored, and text after the line stays with its section. +private func extractEndMarker(_ raw: [UInt16]) -> (Units, Bool) { + var text = Units(raw) + var end = false + while let index = firstIndex(of: endMarker, in: text) { + end = true + let before = stripSectionSeparator(text[.. Units { + var trim = 0 + for token in streamPartialTokens { + var length = min(token.count - 1, content.count) + while length > trim { + if content.suffix(length).elementsEqual(token.prefix(length)) { + trim = length + break + } + length -= 1 + } + } + return trim > 0 ? stripSectionSeparator(content.dropLast(trim)) : content +} + +private func bodyStart(_ raw: Units, _ marker: Int) -> Int { + firstIndex(of: newline, in: raw, from: marker).map { $0 + 1 } ?? raw.endIndex +} + +private func stripSectionSeparator(_ value: Units) -> Units { + if value.count >= 2, value.suffix(2).elementsEqual([carriageReturn, newline]) { + return value.dropLast(2) + } + return value.last == newline ? value.dropLast() : value +} + +/// The deprecated ``/`` XML envelope, kept only to read +/// messages saved before the inline markers. +private func parseLegacyXML(_ raw: Units) -> (content: Units, context: Units?) { + var content = raw + var context: Units? + + // /([\s\S]*)<\/context>\s*$/ + let open = Array("".utf16) + let close = Array("".utf16) + if let closeIndex = lastIndex(of: close, in: raw), + isWhitespace(raw[(closeIndex + close.count)...]), + let openIndex = firstIndex(of: open, in: raw), openIndex + open.count <= closeIndex + { + context = raw[(openIndex + open.count)..]*>([\s\S]*)<\/content>\s*$/ + let contentOpen = Array("".utf16) + if content.starts(with: contentOpen), + let tagEnd = firstIndex(of: [UInt16(ascii: ">")], in: content, from: content.startIndex), + let closeIndex = lastIndex(of: contentClose, in: content), closeIndex >= tagEnd + 1, + isWhitespace(content[(closeIndex + contentClose.count)...]) + { + content = content[(tagEnd + 1).. Int? { + var index = start ?? haystack.startIndex + while index + needle.count <= haystack.endIndex { + if haystack[index..<(index + needle.count)].elementsEqual(needle) { return index } + index += 1 + } + return nil +} + +private func firstIndex(of unit: UInt16, in haystack: Units, from start: Int) -> Int? { + haystack[start...].firstIndex(of: unit) +} + +private func lastIndex(of needle: [UInt16], in haystack: Units) -> Int? { + var index = haystack.endIndex - needle.count + while index >= haystack.startIndex { + if haystack[index..<(index + needle.count)].elementsEqual(needle) { return index } + index -= 1 + } + return nil +} + +private func isWhitespace(_ units: Units) -> Bool { + units.allSatisfy { Unicode.Scalar($0).map(jsWhitespace.contains) ?? false } +} + +private func skipWhitespace(_ units: [UInt16], from start: Int) -> Int { + var index = start + while index < units.count, Unicode.Scalar(units[index]).map(jsWhitespace.contains) ?? false { + index += 1 + } + return index +} diff --git a/packages/swift-lang/Sources/OpenUILang/JSSemantics.swift b/packages/swift-lang/Sources/OpenUILang/JSSemantics.swift index 213b761de1..3726150561 100644 --- a/packages/swift-lang/Sources/OpenUILang/JSSemantics.swift +++ b/packages/swift-lang/Sources/OpenUILang/JSSemantics.swift @@ -161,7 +161,7 @@ private func shortestDigits(_ value: Double) -> (String, Int) { // MARK: - String → Number (ECMAScript StringToNumber) -private let jsWhitespace: Set = [ +let jsWhitespace: Set = [ "\u{0009}", "\u{000A}", "\u{000B}", "\u{000C}", "\u{000D}", "\u{0020}", "\u{00A0}", "\u{1680}", "\u{2000}", "\u{2001}", "\u{2002}", "\u{2003}", "\u{2004}", "\u{2005}", "\u{2006}", "\u{2007}", "\u{2008}", "\u{2009}", "\u{200A}", "\u{2028}", "\u{2029}", "\u{202F}", "\u{205F}", "\u{3000}", diff --git a/packages/swift-lang/Tests/OpenUILangTests/EditAndCloudTests.swift b/packages/swift-lang/Tests/OpenUILangTests/EditAndCloudTests.swift index 2bc81951e7..9bc75e86fc 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/EditAndCloudTests.swift +++ b/packages/swift-lang/Tests/OpenUILangTests/EditAndCloudTests.swift @@ -67,3 +67,92 @@ import Testing editMode: value["editMode"].boolValue) } } + +/// The Cloud message format must split and wrap messages exactly like +/// react-ui's sentinel parser. +@Suite struct CloudMessageConformanceTests { + static let fixtures = Fixtures.load("messages") + + static var cases: [FixtureCase] { + (fixtures["separate"].arrayValue ?? []).map { + FixtureCase(name: $0["name"].stringValue ?? "?", value: $0) + } + } + + @Test(arguments: cases) + func separatesContentAndContext(_ fixture: FixtureCase) { + let parsed = separateContentAndContext(fixture.value["input"].stringValue!) + let expected = fixture.value["expected"] + #expect(parsed.content == expected["content"].stringValue) + #expect(parsed.contextString == expected["contextString"].stringValue) + #expect(parsed.contentHeader == expected["contentHeader"].stringValue) + #expect(parsed.end == (expected["end"].boolValue ?? false)) + } + + @Test func detectsLangSyntax() { + for entry in Self.fixtures["langSyntax"].arrayValue ?? [] { + let input = entry["input"].stringValue! + #expect(hasLangSyntax(input) == entry["expected"].boolValue, "\(input.debugDescription)") + } + #expect(!hasLangSyntax(nil)) + } + + @Test func parsesArtifacts() { + for entry in Self.fixtures["artifacts"].arrayValue ?? [] { + let input = entry["input"].stringValue! + let parsed = parseArtifactSentinel(input) + let expected = entry["expected"] + guard expected != .null else { + #expect(parsed == nil, "\(input.debugDescription)") + continue + } + let header = expected["header"] + #expect(parsed?.header.artifactId == header["artifact_id"].stringValue) + #expect(parsed?.header.type.rawValue == header["type"].stringValue) + #expect(parsed?.header.name == header["name"].stringValue) + #expect(parsed?.header.version == header["version"].stringValue) + #expect(parsed?.program == expected["program"].stringValue) + } + } + + @Test func wraps() { + let wrap = Self.fixtures["wrap"] + #expect(wrapContent("root = X()") == wrap["content"].stringValue) + #expect( + wrapContentWithHeader("root = X()", "]]>openui:content?thesys=true") + == wrap["contentWithHeader"].stringValue) + #expect(wrapContentWithHeader("root = X()", nil) == wrap["contentWithoutHeader"].stringValue) + #expect(wrapContext(#"[{"a":1}]"#) == wrap["context"].stringValue) + } + + /// The two messages react-ui's chat builds (GenUIAssistantMessage). + @Test func buildsChatMessages() throws { + var event = ActionEvent( + type: BuiltinActionType.continueConversation, humanFriendlyMessage: "Book it") + #expect( + continueConversationMessage(event) + == "]]>openui:content\nBook it\n]]>openui:context\n[\"User clicked: Book it\"]") + event.formState = ["form": ["seats": ["value": 2, "componentType": "Input"]]] + #expect( + continueConversationMessage(event) + == #"]]>openui:content\#nBook it\#n]]>openui:context\#n["User clicked: Book it",{"form":{"seats":{"value":2,"componentType":"Input"}}}]"# + ) + + let state: OpenUIObject = ["$tab": "b"] + let saved = messageWithState( + content: "root = X()", contentHeader: "]]>openui:content?thesys=true", state: state) + #expect( + saved == "]]>openui:content?thesys=true\nroot = X()\n]]>openui:context\n[{\"$tab\":\"b\"}]") + #expect( + messageWithState(content: "root = X()", contentHeader: nil, state: [:]) + == wrapContent("root = X()")) + + // Round trip: what was saved comes back as the renderer's initial state. + let parsed = separateContentAndContext(saved) + #expect(parsed.content == "root = X()") + #expect(initialState(fromContext: parsed.contextString) == state) + #expect(initialState(fromContext: #"{"a":1}"#) == ["a": 1]) + #expect(initialState(fromContext: "[null]") == nil) + #expect(initialState(fromContext: "not json") == nil) + } +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/messages.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/messages.json new file mode 100644 index 0000000000..9d86001acf --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/messages.json @@ -0,0 +1,374 @@ +{ + "separate": [ + { + "name": "empty", + "input": "", + "expected": { + "content": "", + "contextString": null + } + }, + { + "name": "plain text", + "input": "Just some text", + "expected": { + "content": "Just some text", + "contextString": null + } + }, + { + "name": "content only", + "input": "]]>openui:content\nroot = Card([])", + "expected": { + "content": "root = Card([])", + "contextString": null, + "contentHeader": "]]>openui:content" + } + }, + { + "name": "content with header attrs", + "input": "]]>openui:content?thesys=true&libraryVersion=0.1.0\nroot = Card([])", + "expected": { + "content": "root = Card([])", + "contextString": null, + "contentHeader": "]]>openui:content?thesys=true&libraryVersion=0.1.0" + } + }, + { + "name": "content and context", + "input": "]]>openui:content\nroot = Card([])\n]]>openui:context\n[{\"f\":1}]", + "expected": { + "content": "root = Card([])", + "contextString": "[{\"f\":1}]", + "contentHeader": "]]>openui:content" + } + }, + { + "name": "context only", + "input": "Hello\n]]>openui:context\n[\"User clicked: Go\"]", + "expected": { + "content": "Hello", + "contextString": "[\"User clicked: Go\"]" + } + }, + { + "name": "context then content", + "input": "]]>openui:context\n[1]\n]]>openui:content\nroot = X()", + "expected": { + "content": "root = X()", + "contextString": null, + "contentHeader": "]]>openui:content" + } + }, + { + "name": "last content wins", + "input": "]]>openui:content\nold\n]]>openui:content\nnew", + "expected": { + "content": "new", + "contextString": null, + "contentHeader": "]]>openui:content" + } + }, + { + "name": "crlf separators", + "input": "]]>openui:content\r\nroot = X()\r\n]]>openui:context\r\n[1]", + "expected": { + "content": "root = X()", + "contextString": "[1]", + "contentHeader": "]]>openui:content\r" + } + }, + { + "name": "end marker", + "input": "]]>openui:content\nroot = X()\n]]>openui:end", + "expected": { + "content": "root = X()", + "contextString": null, + "contentHeader": "]]>openui:content", + "end": true + } + }, + { + "name": "end marker with attrs", + "input": "]]>openui:content\nroot = X()\n]]>openui:end?status=done", + "expected": { + "content": "root = X()", + "contextString": null, + "contentHeader": "]]>openui:content", + "end": true + } + }, + { + "name": "text after end marker", + "input": "]]>openui:content\nroot = X()\n]]>openui:end\ntrailing", + "expected": { + "content": "root = X()\ntrailing", + "contextString": null, + "contentHeader": "]]>openui:content", + "end": true + } + }, + { + "name": "end between sections", + "input": "]]>openui:content\na\n]]>openui:end\n]]>openui:context\n[1]", + "expected": { + "content": "a", + "contextString": "[1]", + "contentHeader": "]]>openui:content", + "end": true + } + }, + { + "name": "two end markers", + "input": "]]>openui:content\na\n]]>openui:end\n]]>openui:end", + "expected": { + "content": "a", + "contextString": null, + "contentHeader": "]]>openui:content", + "end": true + } + }, + { + "name": "crlf before end", + "input": "]]>openui:content\na\r\n]]>openui:end", + "expected": { + "content": "a", + "contextString": null, + "contentHeader": "]]>openui:content", + "end": true + } + }, + { + "name": "partial tail one char", + "input": "]]>openui:content\nroot = X()\n]", + "expected": { + "content": "root = X()", + "contextString": null, + "contentHeader": "]]>openui:content" + } + }, + { + "name": "partial tail sentinel", + "input": "]]>openui:content\nroot = X()\n]]>openui:", + "expected": { + "content": "root = X()", + "contextString": null, + "contentHeader": "]]>openui:content" + } + }, + { + "name": "partial context marker", + "input": "]]>openui:content\nroot = X()\n]]>openui:cont", + "expected": { + "content": "root = X()", + "contextString": null, + "contentHeader": "]]>openui:content" + } + }, + { + "name": "partial end marker", + "input": "]]>openui:content\nroot = X()\n]]>openui:e", + "expected": { + "content": "root = X()", + "contextString": null, + "contentHeader": "]]>openui:content" + } + }, + { + "name": "bracket that isn't a marker", + "input": "]]>openui:content\nx = [1, 2]", + "expected": { + "content": "x = [1, 2", + "contextString": null, + "contentHeader": "]]>openui:content" + } + }, + { + "name": "marker header without newline", + "input": "]]>openui:content", + "expected": { + "content": "", + "contextString": null, + "contentHeader": "]]>openui:content" + } + }, + { + "name": "markers on one line", + "input": "]]>openui:content]]>openui:context\n[1]", + "expected": { + "content": "", + "contextString": "[1]", + "contentHeader": "]]>openui:content]]>openui:context" + } + }, + { + "name": "emoji", + "input": "]]>openui:content\nroot = TextContent(\"🙂 hi\")\n]]>openui:context\n[\"🎉\"]", + "expected": { + "content": "root = TextContent(\"🙂 hi\")", + "contextString": "[\"🎉\"]", + "contentHeader": "]]>openui:content" + } + }, + { + "name": "legacy xml", + "input": "root = X()\n[{\"a\":1}]", + "expected": { + "content": "root = X()", + "contextString": "[{\"a\":1}]" + } + }, + { + "name": "legacy content only", + "input": "root = X() ", + "expected": { + "content": "root = X()", + "contextString": null + } + }, + { + "name": "legacy context only", + "input": "text\n[\"x\"]\n", + "expected": { + "content": "text", + "contextString": "[\"x\"]" + } + }, + { + "name": "legacy unclosed", + "input": "root = X()", + "expected": { + "content": "root = X()", + "contextString": null + } + }, + { + "name": "legacy text after context", + "input": "[1] more", + "expected": { + "content": "[1] more", + "contextString": null + } + } + ], + "langSyntax": [ + { + "input": "```openui-lang\nroot = X()\n```", + "expected": true + }, + { + "input": "root = X()", + "expected": true + }, + { + "input": "root=X()", + "expected": true + }, + { + "input": " root = X()", + "expected": true + }, + { + "input": "intro\n\troot = X()", + "expected": true + }, + { + "input": "intro\n\n root\n= X()", + "expected": true + }, + { + "input": "rooted = 1", + "expected": false + }, + { + "input": "x root = 1", + "expected": false + }, + { + "input": "Just text", + "expected": false + }, + { + "input": "", + "expected": false + } + ], + "artifacts": [ + { + "input": "]]>openui:artifact {\"artifact_id\":\"a1\",\"type\":\"slides\",\"name\":\"Deck\",\"version\":\"2\"}\nroot = X()", + "expected": { + "header": { + "artifact_id": "a1", + "type": "slides", + "name": "Deck", + "version": "2" + }, + "program": "root = X()" + } + }, + { + "input": "]]>openui:artifact {\"artifact_id\":\"a2\",\"type\":\"presentation\"}\nprogram", + "expected": { + "header": { + "artifact_id": "a2", + "type": "slides" + }, + "program": "program" + } + }, + { + "input": "]]>openui:artifact {\"artifact_id\":\"a3\",\"type\":\"report\",\"name\":\"\"}", + "expected": { + "header": { + "artifact_id": "a3", + "type": "report" + }, + "program": "" + } + }, + { + "input": "]]>openui:artifact {\"artifact_id\":\"\",\"type\":\"report\"}\nx", + "expected": null + }, + { + "input": "]]>openui:artifact {\"type\":\"report\"}\nx", + "expected": null + }, + { + "input": "]]>openui:artifact {\"artifact_id\":\"a4\",\"type\":\"video\"}\nx", + "expected": null + }, + { + "input": "]]>openui:artifact {\"artifact_id\":\"a5\",\"type\":\"report\",\"version\":7}\nx", + "expected": { + "header": { + "artifact_id": "a5", + "type": "report" + }, + "program": "x" + } + }, + { + "input": "]]>openui:artifact not json\nx", + "expected": null + }, + { + "input": "]]>openui:artifact []\nx", + "expected": null + }, + { + "input": "]]>openui:artifact{\"artifact_id\":\"a6\",\"type\":\"report\"}\nx", + "expected": null + }, + { + "input": "]]>openui:content\nroot = X()", + "expected": null + } + ], + "wrap": { + "content": "]]>openui:content\nroot = X()", + "contentWithHeader": "]]>openui:content?thesys=true\nroot = X()", + "contentWithoutHeader": "]]>openui:content\nroot = X()", + "context": "\n]]>openui:context\n[{\"a\":1}]" + } +} From a0805180cbb691489d9b0940650d614abcbbdd32 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:19:38 +0530 Subject: [PATCH 22/52] feat(swift-lang): highlight code like react-ui CodeBlock uses Prism's vscDarkPlus colors and gets react-ui's copy button (shown on hover on the Mac, as on the web). Fenced code in Markdown keeps its language, uses vscDarkPlus or oneLight with the color scheme and is trimmed like react-ui's; image lines render as images. Highlighting comes from a small tokenizer for common languages rather than Prism's grammars. --- .../Components/ContentComponents.swift | 88 ++++- .../Sources/OpenUISwiftUI/Support.swift | 36 +- .../OpenUISwiftUI/SyntaxHighlighter.swift | 364 ++++++++++++++++++ .../OpenUISwiftUITests/RendererTests.swift | 81 ++++ 4 files changed, 551 insertions(+), 18 deletions(-) create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/SyntaxHighlighter.swift diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift index 2124e1d0ad..5c3a900027 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift @@ -222,28 +222,90 @@ private struct Banner: View { // MARK: - Code +/// A code block like react-ui's: Prism's `vscDarkPlus` colors (in light mode +/// too), and a copy button in the corner (on hover on the Mac, as on the web). struct CodeBlockView: View { let props: ComponentProps - @Environment(\.openUITheme) private var theme var body: some View { - VStack(alignment: .leading, spacing: 6) { - if let language = props.string("language"), !language.isEmpty { - Text(language).font(.caption.weight(.medium)).foregroundStyle(.secondary) - } - ScrollView(.horizontal, showsIndicators: false) { - Text(props.text("codeString")) - .font(.system(.callout, design: .monospaced)) - .textSelection(.enabled) - .fixedSize(horizontal: true, vertical: false) - } + CodeBlockContent( + code: props.text("codeString"), language: props.string("language"), + theme: .darkPlus) + } +} + +/// Highlighted code with a copy button, shared with code in markdown. +struct CodeBlockContent: View { + let code: String + let language: String? + let theme: SyntaxHighlighter.Theme + @State private var copied = false + @State private var hovering = false + + var body: some View { + ScrollView(.horizontal, showsIndicators: false) { + Text(SyntaxHighlighter.highlight(code, language: language, theme: theme)) + .font(.system(size: 13, design: .monospaced)) + .lineSpacing(4) + .textSelection(.enabled) + .fixedSize(horizontal: true, vertical: false) + .padding(13) } - .padding(12) .frame(maxWidth: .infinity, alignment: .leading) - .background(theme.sunkSurface, in: RoundedRectangle(cornerRadius: theme.smallCornerRadius)) + .background(theme.background, in: RoundedRectangle(cornerRadius: 8)) + .overlay(alignment: .topTrailing) { + copyButton + .padding(8) + .opacity(showsCopyButton ? 1 : 0) + .animation(.easeInOut(duration: 0.2), value: showsCopyButton) + } + .onHover { hovering = $0 } + } + + private var showsCopyButton: Bool { + #if os(macOS) + hovering || copied + #else + true + #endif + } + + private var copyButton: some View { + Button { + copyToPasteboard(code) + copied = true + Task { + try? await Task.sleep(for: .seconds(1)) + copied = false + } + } label: { + Image(systemName: copied ? "checkmark" : "doc.on.doc") + .font(.caption.weight(.semibold)) + .contentTransition(.symbolEffect(.replace)) + .foregroundStyle(copied ? Color.green : Color.primary) + .frame(width: 26, height: 26) + .background( + copied ? Color.green.opacity(0.15) : Color.platformElevatedBackground, + in: RoundedRectangle(cornerRadius: 6) + ) + .overlay(RoundedRectangle(cornerRadius: 6).strokeBorder(Color.primary.opacity(0.12))) + } + .buttonStyle(.plain) + .accessibilityLabel(copied ? "Copied to clipboard" : "Copy code") } } +/// Puts `text` on the system pasteboard. +@MainActor +func copyToPasteboard(_ text: String) { + #if os(macOS) + NSPasteboard.general.clearContents() + NSPasteboard.general.setString(text, forType: .string) + #else + UIPasteboard.general.string = text + #endif +} + // MARK: - Images struct ImageView: View { diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift index 53157fe86e..44026aeada 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift @@ -119,7 +119,9 @@ struct MarkdownBlocks: View { case bullet(String) case numbered(String, String) case quote(String) - case code(String) + case code(language: String?, String) + /// A line that is only `![alt](url)`. + case image(alt: String, url: String) /// `$$ … $$` math. There's no native TeX renderer, so it shows as source. case math(String) case table(header: [String], rows: [[String]]) @@ -130,6 +132,7 @@ struct MarkdownBlocks: View { let blocks: [Block] /// Renders `[n]` markers as citations (TextContent does, MarkDownRenderer doesn't). let citations: Bool + @Environment(\.colorScheme) private var colorScheme init(_ source: String, citations: Bool = false) { blocks = Self.parse(source) @@ -170,8 +173,12 @@ struct MarkdownBlocks: View { .foregroundStyle(.secondary) .padding(.leading, 10) .overlay(alignment: .leading) { Rectangle().fill(.secondary.opacity(0.4)).frame(width: 3) } - case .code(let text): - Text(text).font(.system(.callout, design: .monospaced)) + case .code(let language, let text): + // react-ui's markdown uses the CodeBlock, with oneLight in light mode. + CodeBlockContent( + code: text, language: language, theme: colorScheme == .dark ? .darkPlus : .oneLight) + case .image(let alt, let url): + RemoteImage(src: url, alt: alt, fit: true) case .math(let tex): Text(tex) .font(.system(.callout, design: .monospaced)) @@ -203,6 +210,7 @@ struct MarkdownBlocks: View { var blocks: [Block] = [] var paragraph: [String] = [] var code: [String]? = nil + var codeLanguage: String? var math: [String]? = nil var table: [[String]] = [] @@ -266,11 +274,13 @@ struct MarkdownBlocks: View { } if line.hasPrefix("```") { if let lines = code { - blocks.append(.code(lines.joined(separator: "\n"))) + blocks.append(.code(language: codeLanguage, codeBlockText(lines))) code = nil } else { flushParagraph() code = [] + let info = line.dropFirst(3).split(separator: " ").first.map(String.init) + codeLanguage = info?.isEmpty == false ? info : nil } continue } @@ -298,6 +308,9 @@ struct MarkdownBlocks: View { flushParagraph() blocks.append( .numbered(String(line[...dot]), String(line[line.index(dot, offsetBy: 2)...]))) + } else if let image = Self.image(line) { + flushParagraph() + blocks.append(image) } else if line.hasPrefix(">") { flushParagraph() blocks.append(.quote(String(line.dropFirst()).trimmingCharacters(in: .whitespaces))) @@ -307,10 +320,23 @@ struct MarkdownBlocks: View { } if !table.isEmpty { flushTable() } if let lines = math { blocks.append(.math(lines.joined(separator: "\n"))) } - if let lines = code { blocks.append(.code(lines.joined(separator: "\n"))) } + if let lines = code { blocks.append(.code(language: codeLanguage, codeBlockText(lines))) } flushParagraph() return blocks } + + /// A fenced block's text, trimmed like react-ui's (`String(children).trim()`). + private static func codeBlockText(_ lines: [String]) -> String { + lines.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines) + } + + /// `![alt](url)` (optionally with a title) alone on a line. + static func image(_ line: String) -> Block? { + guard + let match = line.wholeMatch(of: /!\[([^\]]*)\]\((\S+?)(?:\s+"[^"]*")?\)/) + else { return nil } + return .image(alt: String(match.1), url: String(match.2)) + } } /// Lays children out in rows, wrapping to the next row when one is full. diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/SyntaxHighlighter.swift b/packages/swift-lang/Sources/OpenUISwiftUI/SyntaxHighlighter.swift new file mode 100644 index 0000000000..39ec24c8b4 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/SyntaxHighlighter.swift @@ -0,0 +1,364 @@ +import SwiftUI + +/// Syntax colors for code, standing in for react-ui's Prism highlighting: the +/// same token kinds and the same two themes (`vscDarkPlus` for `CodeBlock`, +/// `oneLight` or `vscDarkPlus` for code in markdown). A small tokenizer +/// instead of a dependency: comments, strings, numbers, keywords, calls, types, +/// properties, JSON keys and markup tags cover what models write. +enum SyntaxHighlighter { + enum Token: Equatable { + case plain, comment, string, number, keyword, control, constant, function, type, property + case tag, attribute, punctuation + } + + /// Colors per token kind, from react-syntax-highlighter's Prism themes. + struct Theme: Sendable { + var background: Color + var plain: Color + var colors: [Token: Color] + /// Prism themes color a language's plain words differently, e.g. + /// `vscDarkPlus` shows JavaScript variables in light blue. + var languagePlain: [String: Color] = [:] + + func color(_ token: Token, language: String?) -> Color { + if token == .plain { return language.flatMap { languagePlain[$0.lowercased()] } ?? plain } + return colors[token] ?? plain + } + + static let darkPlus = Theme( + background: hex(0x1E1E1E), plain: hex(0xD4D4D4), + colors: [ + .comment: hex(0x6A9955), .string: hex(0xCE9178), .number: hex(0xB5CEA8), + .keyword: hex(0x569CD6), .control: hex(0xC586C0), .constant: hex(0x569CD6), + .function: hex(0xDCDCAA), .type: hex(0x4EC9B0), .property: hex(0x9CDCFE), + .tag: hex(0x569CD6), .attribute: hex(0x9CDCFE), .punctuation: hex(0xD4D4D4), + ], + languagePlain: [ + "javascript": hex(0x9CDCFE), "js": hex(0x9CDCFE), "jsx": hex(0x9CDCFE), + "typescript": hex(0x9CDCFE), "ts": hex(0x9CDCFE), "tsx": hex(0x9CDCFE), + "css": hex(0xCE9178), + ]) + + static let oneLight = Theme( + background: hsl(230, 1, 98), plain: hsl(230, 8, 24), + colors: [ + .comment: hsl(230, 4, 64), .string: hsl(119, 34, 47), .number: hsl(35, 99, 36), + .keyword: hsl(301, 63, 40), .control: hsl(301, 63, 40), .constant: hsl(35, 99, 36), + .function: hsl(221, 87, 60), .type: hsl(35, 99, 36), .property: hsl(5, 74, 59), + .tag: hsl(5, 74, 59), .attribute: hsl(35, 99, 36), .punctuation: hsl(230, 8, 24), + ]) + + private static func hex(_ value: Int) -> Color { + Color( + red: Double((value >> 16) & 0xFF) / 255, green: Double((value >> 8) & 0xFF) / 255, + blue: Double(value & 0xFF) / 255) + } + + private static func hsl(_ hue: Double, _ saturation: Double, _ lightness: Double) -> Color { + let s = saturation / 100 + let l = lightness / 100 + let brightness = l + s * min(l, 1 - l) + return Color( + hue: hue / 360, saturation: brightness == 0 ? 0 : 2 * (1 - l / brightness), + brightness: brightness) + } + } + + /// `code` as colored text. + static func highlight(_ code: String, language: String?, theme: Theme) -> AttributedString { + var result = AttributedString() + for (text, token) in tokenize(code, language: language) { + var run = AttributedString(text) + run.foregroundColor = theme.color(token, language: language) + result += run + } + return result + } + + // MARK: Tokenizing + + /// The code split into colored runs. Joining the runs gives back `code`. + static func tokenize(_ code: String, language: String?) -> [(String, Token)] { + let grammar = Grammar(language) + let chars = Array(code) + var runs: [(String, Token)] = [] + var plain = "" + var index = 0 + + func emit(_ end: Int, _ token: Token) { + if !plain.isEmpty { + runs.append((plain, .plain)) + plain = "" + } + runs.append((String(chars[index.. Bool { + let prefix = Array(prefix) + return position + prefix.count <= chars.count + && Array(chars[position.. Int { chars[from...].firstIndex(of: "\n") ?? chars.count } + + while index < chars.count { + let char = chars[index] + if grammar.markup { + if char == "<" { + if starts("", from: index + 4, in: chars) + emit(end, .comment) + continue + } + // ``. + var end = index + 1 + if end < chars.count, chars[end] == "/" { end += 1 } + while end < chars.count, + chars[end].isLetter || chars[end].isNumber || "-:".contains(chars[end]) + { + end += 1 + } + if end > index + 1 { + emit(end, .tag) + continue + } + } + if char == "=" || char == ">" || char == "/" { + emit(index + 1, .punctuation) + continue + } + if char == "\"" || char == "'" { + emit(stringEnd(chars, from: index, quote: char), .string) + continue + } + if char.isLetter, isInsideTag(chars, index) { + var end = index + while end < chars.count, + chars[end].isLetter || chars[end].isNumber || "-:".contains(chars[end]) + { + end += 1 + } + emit(end, .attribute) + continue + } + plain.append(char) + index += 1 + continue + } + + // Comments. + if grammar.lineComments.contains(where: { starts($0, at: index) }) { + emit(lineEnd(index), .comment) + continue + } + if grammar.blockComments, starts("/*", at: index) { + emit(closing("*/", from: index + 2, in: chars), .comment) + continue + } + // Strings, including triple-quoted ones. + if grammar.quotes.contains(char) { + let triple = String(repeating: char, count: 3) + if grammar.tripleQuotes, starts(triple, at: index) { + emit(closing(triple, from: index + 3, in: chars), .string) + } else { + let end = stringEnd(chars, from: index, quote: char) + // A JSON key is a string followed by a colon. + var next = end + while next < chars.count, chars[next] == " " { next += 1 } + let isKey = grammar.json && next < chars.count && chars[next] == ":" + emit(end, isKey ? .property : .string) + } + continue + } + // Numbers. + if char.isNumber || (char == "." && index + 1 < chars.count && chars[index + 1].isNumber), + index == 0 || !isIdentifierCharacter(chars[index - 1]) + { + var end = index + 1 + while end < chars.count, + chars[end].isHexDigit || "xXoObB_.".contains(chars[end]) + || ((chars[end] == "+" || chars[end] == "-") && "eE".contains(chars[end - 1])) + { + end += 1 + } + emit(end, .number) + continue + } + // Words: keywords, constants, calls, types and properties. + if isIdentifierStart(char) { + var end = index + 1 + while end < chars.count, isIdentifierCharacter(chars[end]) { end += 1 } + let word = String(chars[index.. 0, chars[index - 1] == "." { + token = .property + } else if word.first?.isUppercase == true, grammar.typesAreCapitalized { + token = .type + } else { + token = .plain + } + emit(end, token) + continue + } + // Operators and punctuation have their own color; whitespace has none. + if char.isWhitespace { + plain.append(char) + index += 1 + } else { + emit(index + 1, .punctuation) + } + } + if !plain.isEmpty { runs.append((plain, .plain)) } + return runs + } + + private static func isIdentifierStart(_ char: Character) -> Bool { + char.isLetter || char == "_" || char == "$" + } + + private static func isIdentifierCharacter(_ char: Character) -> Bool { + char.isLetter || char.isNumber || char == "_" || char == "$" + } + + /// The end of a quoted string, after its closing quote (or the line's end + /// for an unfinished one, as happens mid-stream). + private static func stringEnd(_ chars: [Character], from start: Int, quote: Character) -> Int { + var index = start + 1 + while index < chars.count { + if chars[index] == "\\" { + index += 2 + continue + } + if chars[index] == quote { return index + 1 } + if chars[index] == "\n", quote != "`" { return index } + index += 1 + } + return chars.count + } + + /// The end of a block (comment or triple-quoted string) closed by `marker`. + private static func closing(_ marker: String, from start: Int, in chars: [Character]) -> Int { + let marker = Array(marker) + var index = start + while index + marker.count <= chars.count { + if Array(chars[index..`. + private static func isInsideTag(_ chars: [Character], _ index: Int) -> Bool { + var position = index - 1 + while position >= 0 { + if chars[position] == ">" { return false } + if chars[position] == "<" { return true } + position -= 1 + } + return false + } + + /// What a language's code looks like, as far as coloring goes. + struct Grammar { + var keywords: Set = [] + var control: Set = [] + var constants: Set = [ + "true", "false", "null", "nil", "None", "True", "False", "undefined", + ] + var lineComments = ["//"] + var blockComments = true + var quotes: Set = ["\"", "'", "`"] + var tripleQuotes = false + var typesAreCapitalized = true + var json = false + var markup = false + + init(_ language: String?) { + let control: Set = [ + "if", "else", "for", "while", "do", "switch", "case", "default", "break", "continue", + "return", "try", "catch", "finally", "throw", "throws", "guard", "import", "export", + "from", "await", "yield", "in", "of", "elif", "except", "raise", "with", "pass", "match", + "loop", "defer", "go", "select", "goto", "then", "fi", "done", "esac", "unless", "until", + "begin", "rescue", "ensure", "end", + ] + self.control = control + switch (language ?? "").lowercased() { + case "json", "jsonc": + keywords = [] + self.control = [] + lineComments = [] + blockComments = false + quotes = ["\""] + json = true + typesAreCapitalized = false + case "html", "xml", "svg", "vue": + markup = true + case "python", "py": + keywords = [ + "def", "class", "lambda", "global", "nonlocal", "assert", "del", "async", "as", "is", + "not", "and", "or", "print", + ] + lineComments = ["#"] + blockComments = false + quotes = ["\"", "'"] + tripleQuotes = true + case "ruby", "rb": + keywords = [ + "def", "class", "module", "self", "do", "and", "or", "not", "attr_accessor", "require", + ] + lineComments = ["#"] + blockComments = false + quotes = ["\"", "'"] + case "bash", "sh", "shell", "zsh", "console": + keywords = ["export", "local", "function", "echo", "cd", "set", "unset", "source"] + lineComments = ["#"] + blockComments = false + quotes = ["\"", "'"] + typesAreCapitalized = false + case "yaml", "yml", "toml", "ini": + keywords = [] + self.control = [] + lineComments = ["#"] + blockComments = false + quotes = ["\"", "'"] + typesAreCapitalized = false + case "sql": + let words = [ + "select", "from", "where", "join", "left", "right", "inner", "outer", "on", "group", "by", + "order", "having", "limit", "insert", "into", "values", "update", "set", "delete", + "create", "table", "index", "as", "and", "or", "not", "null", "distinct", "union", + "primary", "key", "references", "alter", "drop", "count", "sum", "avg", "min", "max", + ] + keywords = Set(words + words.map { $0.uppercased() }) + self.control = [] + lineComments = ["--"] + quotes = ["'", "\""] + typesAreCapitalized = false + default: + // C-family and most others: JS/TS, Swift, Kotlin, Java, Go, Rust, C, C++, C#, PHP. + keywords = [ + "var", "let", "const", "function", "func", "fn", "def", "class", "struct", "enum", + "interface", "protocol", "extension", "type", "typealias", "impl", "trait", "mod", + "pub", "private", "public", "protected", "internal", "fileprivate", "static", "final", + "override", "abstract", "async", "new", "this", "self", "super", "extends", + "implements", "package", "namespace", "using", "val", "fun", "object", "data", "sealed", + "open", "lateinit", "mut", "ref", "where", "as", "is", "instanceof", "typeof", "void", + "int", "float", "double", "char", "bool", "boolean", "string", "long", "short", "byte", + "unsigned", "signed", "const_cast", "auto", "inout", "some", "any", "readonly", "declare", + "keyof", "get", "set", "init", "deinit", "subscript", "mutating", "weak", "unowned", + "lazy", + "chan", "map", "range", "echo", + ] + } + } + } +} diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 2814eff563..065f512381 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -372,3 +372,84 @@ let globalTestLibrary = SwiftUILibrary( #expect(SliderView.errors([.nan], minimum: 0, maximum: 100) == ["Invalid number"]) } } + +/// The highlighter's token kinds, standing in for Prism's. +@Suite struct SyntaxHighlighterTests { + func kinds(_ code: String, _ language: String) -> [String: SyntaxHighlighter.Token] { + var kinds: [String: SyntaxHighlighter.Token] = [:] + for (text, token) in SyntaxHighlighter.tokenize(code, language: language) + where !text.trimmingCharacters(in: .whitespaces).isEmpty { + kinds[text] = token + } + return kinds + } + + @Test func keepsTheSourceIntact() { + for (code, language) in [ + ("const total = items.map(x => x * 2) // twice\n", "ts"), + ("def f(x):\n \"\"\"doc\"\"\"\n return x # done", "python"), + ("{\"a\": [1, true, null]}", "json"), ("Hi", "html"), + ("SELECT name FROM users WHERE id = 3", "sql"), ("let s = \"unfinished", "swift"), + ] { + let joined = SyntaxHighlighter.tokenize(code, language: language).map(\.0).joined() + #expect(joined == code) + } + } + + @Test func classifiesTokensLikePrism() { + let ts = kinds("import { x } from \"y\"\nconst total = sum(3.5) // note", "ts") + #expect(ts["import"] == .control) + #expect(ts["const"] == .keyword) + #expect(ts["\"y\""] == .string) + #expect(ts["sum"] == .function) + #expect(ts["3.5"] == .number) + #expect(ts["// note"] == .comment) + #expect(ts["total"] == .plain) + + let python = kinds("def greet(name):\n return None # nothing", "python") + #expect(python["def"] == .keyword) + #expect(python["greet"] == .function) + #expect(python["return"] == .control) + #expect(python["None"] == .constant) + #expect(python["# nothing"] == .comment) + + let json = kinds("{\"name\": \"Ada\", \"age\": 36, \"ok\": true}", "json") + #expect(json["\"name\""] == .property) + #expect(json["\"Ada\""] == .string) + #expect(json["36"] == .number) + #expect(json["true"] == .constant) + + let html = kinds("Hi", "html") + #expect(html[" Date: Wed, 7 Oct 2026 13:19:38 +0530 Subject: [PATCH 23/52] feat(swift-lang): add react-ui's gallery mosaic and viewer ImageGallery lays out the first five images in react-ui's grid templates, the first one large, with its narrow templates below 520pt (react-ui switches on a 768px viewport, and a chat column is narrower than its window). Past five images it shows a Show All button. Tapping an image opens a viewer with one image per page (swipe, or the arrow keys), react-ui's thumbnail strip, and the image's details under it. react-ui sizes the grid from the loaded images, up to 376px. The mosaic uses a fixed shape instead so it doesn't jump when the images arrive. --- .../Components/ContentComponents.swift | 321 +++++++++++++++++- .../OpenUISwiftUITests/RendererTests.swift | 36 ++ 2 files changed, 346 insertions(+), 11 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift index 5c3a900027..951fc06d25 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift @@ -324,28 +324,325 @@ struct ImageBlockView: View { } } +/// react-ui's ImageGallery: the first five images in a mosaic, a "Show All" +/// button when there are more, and a viewer with every image. Tapping an image +/// opens the viewer on it. struct ImageGalleryView: View { let props: ComponentProps + @State private var selected = 0 + @State private var showsViewer = false @Environment(\.openUITheme) private var theme var body: some View { - ScrollView(.horizontal, showsIndicators: false) { - HStack(alignment: .top, spacing: theme.spacing) { - ForEach(Array(props.array("images").enumerated()), id: \.offset) { _, image in - VStack(alignment: .leading, spacing: 4) { - RemoteImage(src: image["src"].stringValue, alt: displayText(image["alt"])) - .frame(width: 220, height: 150) - .clipped() - let details = displayText(image["details"]) + let images = props.array("images") + if !images.isEmpty { + GalleryMosaic { + ForEach(Array(images.prefix(GalleryMosaic.maxImages).enumerated()), id: \.offset) { + index, image in + Button { + selected = index + showsViewer = true + } label: { + GalleryTile(src: image["src"].stringValue) + } + .buttonStyle(.plain) + .accessibilityLabel(galleryImageLabel(image, index)) + } + } + .clipShape(RoundedRectangle(cornerRadius: theme.cornerRadius)) + .overlay(alignment: .bottomTrailing) { + if images.count > GalleryMosaic.maxImages { + // Filled by hand: over a photo, a bordered button that loses its + // fill in an inactive Mac window can't be read. + Button { + showsViewer = true + } label: { + Text("Show All") + .font(.footnote.weight(.medium)) + .foregroundStyle(theme.onAccent) + .padding(.horizontal, 10) + .padding(.vertical, 5) + .background(theme.accent, in: RoundedRectangle(cornerRadius: theme.smallCornerRadius)) + } + .buttonStyle(.plain) + .padding(5) + } + } + .sheet(isPresented: $showsViewer) { + GalleryViewer(images: images, selected: $selected) + .environment(\.openUITheme, theme) + } + } + } +} + +private func galleryImageLabel(_ image: OpenUIValue, _ index: Int) -> String { + let alt = displayText(image["alt"]) + return alt.isEmpty ? "Gallery image \(index + 1)" : alt +} + +/// A mosaic image that zooms in a little under the pointer, as react-ui's do. +private struct GalleryTile: View { + let src: String? + @State private var hovering = false + + var body: some View { + RemoteImage(src: src, alt: "", rounded: false) + .scaleEffect(hovering ? 1.05 : 1) + .clipped() + .contentShape(Rectangle()) + .onHover { hovering in + withOpenUIAnimation(.easeOut(duration: 0.3)) { self.hovering = hovering } + } + } +} + +/// Lays out up to five gallery images like react-ui's grid templates: one or +/// two side by side, otherwise the first image large and the rest in two rows +/// beside it (or, when narrow, in rows under it). +struct GalleryMosaic: Layout { + static let maxImages = 5 + /// react-ui caps the grid at 376px. + static let maxHeight: CGFloat = 376 + /// react-ui's `space-s`. + static let gap: CGFloat = 8 + /// react-ui switches to its narrow templates under a 768px viewport. A chat + /// column is much narrower than the window it is in, so this goes by the + /// gallery's own width. + static let narrowWidth: CGFloat = 520 + + /// A CSS grid template: column weights (`fr`), a row count, and each image's + /// column, row and spans. + struct Template: Equatable { + var columns: [CGFloat] + var rows: Int + var cells: [Cell] + + struct Cell: Equatable { + var column: Int + var row: Int + var columnSpan = 1 + var rowSpan = 1 + } + } + + static func template(count: Int, narrow: Bool) -> Template { + typealias Cell = Template.Cell + switch min(count, maxImages) { + case 0: return Template(columns: [1], rows: 1, cells: []) + case 1: return Template(columns: [1], rows: 1, cells: [Cell(column: 0, row: 0)]) + case 2: + return Template( + columns: [1, 1], rows: 1, cells: [Cell(column: 0, row: 0), Cell(column: 1, row: 0)]) + case 3 where narrow: + return Template( + columns: [1, 1], rows: 2, + cells: [ + Cell(column: 0, row: 0, columnSpan: 2), Cell(column: 0, row: 1), Cell(column: 1, row: 1), + ]) + case 3: + return Template( + columns: [1, 1], rows: 2, + cells: [ + Cell(column: 0, row: 0, rowSpan: 2), Cell(column: 1, row: 0), Cell(column: 1, row: 1), + ]) + case 4: + return Template( + columns: [1, 1, 1, 1], rows: 2, + cells: [ + Cell(column: 0, row: 0, columnSpan: 2, rowSpan: 2), + Cell(column: 2, row: 0, columnSpan: 2), + Cell(column: 2, row: 1), Cell(column: 3, row: 1), + ]) + case _ where narrow: + return Template( + columns: Array(repeating: 1, count: 6), rows: 2, + cells: [ + Cell(column: 0, row: 0, columnSpan: 3), Cell(column: 3, row: 0, columnSpan: 3), + Cell(column: 0, row: 1, columnSpan: 2), Cell(column: 2, row: 1, columnSpan: 2), + Cell(column: 4, row: 1, columnSpan: 2), + ]) + default: + return Template( + columns: [2, 1, 1], rows: 2, + cells: [ + Cell(column: 0, row: 0, rowSpan: 2), Cell(column: 1, row: 0), Cell(column: 2, row: 0), + Cell(column: 1, row: 1), Cell(column: 2, row: 1), + ]) + } + } + + /// react-ui's grid takes its height from the images, up to 376px. That + /// isn't known until they load, so this uses a fixed shape instead: no jump + /// when they arrive. + static func height(width: CGFloat, count: Int) -> CGFloat { + let ratio: CGFloat = + switch count { + case 1: 0.6 + case 2: 0.45 + default: width < narrowWidth ? 0.8 : 0.55 + } + return min(maxHeight, (width * ratio).rounded()) + } + + /// Each image's frame, in order. + static func frames(count: Int, in bounds: CGRect) -> [CGRect] { + let template = template(count: count, narrow: bounds.width < narrowWidth) + let unit = + (bounds.width - gap * CGFloat(template.columns.count - 1)) / template.columns.reduce(0, +) + let rowHeight = (bounds.height - gap * CGFloat(template.rows - 1)) / CGFloat(template.rows) + func x(_ column: Int) -> CGFloat { + bounds.minX + template.columns.prefix(column).reduce(0, +) * unit + gap * CGFloat(column) + } + return template.cells.map { cell in + let columns = template.columns[cell.column.. CGSize { + // Without a usable width (an unbounded stack), fall back to a phone's. + let width = proposal.width.flatMap { $0.isFinite ? $0 : nil } ?? 360 + return CGSize(width: width, height: Self.height(width: width, count: subviews.count)) + } + + func placeSubviews( + in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout () + ) { + for (subview, frame) in zip(subviews, Self.frames(count: subviews.count, in: bounds)) { + subview.place(at: frame.origin, proposal: ProposedViewSize(frame.size)) + } + } +} + +/// react-ui's gallery modal: every image, one at a time, over a strip of +/// thumbnails. Swipe or use the arrow keys to move between them. +struct GalleryViewer: View { + let images: [OpenUIValue] + @Binding var selected: Int + @State private var page: Int? + @FocusState private var focused: Bool + @Environment(\.dismiss) private var dismiss + @Environment(\.openUITheme) private var theme + + init(images: [OpenUIValue], selected: Binding) { + self.images = images + _selected = selected + _page = State(initialValue: selected.wrappedValue) + } + + var body: some View { + VStack(spacing: 24) { + HStack { + Text("All Photos").font(.headline) + Spacer() + Button { + dismiss() + } label: { + Image(systemName: "xmark") + .font(.footnote.weight(.semibold)) + .frame(width: 28, height: 28) + .background( + theme.sunkSurface, in: RoundedRectangle(cornerRadius: theme.smallCornerRadius)) + } + .buttonStyle(.plain) + .keyboardShortcut(.cancelAction) + .accessibilityLabel("Close gallery") + } + .padding(.horizontal, 24) + pages + thumbnails + } + .padding(.vertical, 24) + #if os(macOS) + .frame(minWidth: 560, idealWidth: 720, minHeight: 520, idealHeight: 640) + #endif + .focusable() + .focusEffectDisabled() + .focused($focused) + .onAppear { focused = true } + .onKeyPress(.leftArrow) { show(selected - 1) } + .onKeyPress(.rightArrow) { show(selected + 1) } + .onChange(of: page) { _, page in + if let page { selected = page } + } + } + + /// The images full size, one page each. Pages have a fixed size, so the + /// lazy stack never has to re-measure anything while it scrolls. + private var pages: some View { + ScrollView(.horizontal) { + LazyHStack(spacing: 0) { + ForEach(images.indices, id: \.self) { index in + let details = displayText(images[index]["details"]) + VStack(spacing: 8) { + RemoteImage( + src: images[index]["src"].stringValue, alt: galleryImageLabel(images[index], index), + fit: true + ) + .frame(maxHeight: .infinity) if !details.isEmpty { - Text(details).font(.caption).foregroundStyle(.secondary).frame( - width: 220, alignment: .leading) + Text(details).font(.footnote).foregroundStyle(.secondary) + .multilineTextAlignment(.center) + } + } + .padding(.horizontal, 24) + .containerRelativeFrame([.horizontal, .vertical]) + .id(index) + } + } + .scrollTargetLayout() + } + .scrollTargetBehavior(.paging) + .scrollPosition(id: $page) + .scrollIndicators(.never) + } + + private var thumbnails: some View { + ScrollViewReader { proxy in + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: GalleryMosaic.gap) { + ForEach(images.indices, id: \.self) { index in + let isSelected = index == selected + Button { + page = index + } label: { + RemoteImage(src: images[index]["src"].stringValue, alt: "") + .frame(height: 116) + .containerRelativeFrame(.horizontal) { width, _ in + // Thumbnails share the row, but are at least 174 wide. + let count = CGFloat(images.count) + return max(174, (width - 48 - GalleryMosaic.gap * (count - 1)) / count) + } + .opacity(isSelected ? 1 : 0.6) + .overlay( + RoundedRectangle(cornerRadius: theme.smallCornerRadius) + .strokeBorder(isSelected ? theme.accent : .clear)) } + .buttonStyle(.plain) + .accessibilityLabel(galleryImageLabel(images[index], index)) + .accessibilityAddTraits(isSelected ? .isSelected : []) + .id(index) } } + .padding(.horizontal, 24) + } + .onAppear { proxy.scrollTo(selected, anchor: .center) } + .onChange(of: selected) { _, selected in + withOpenUIAnimation(Motion.reveal) { proxy.scrollTo(selected, anchor: .center) } } } } + + private func show(_ index: Int) -> KeyPress.Result { + guard images.indices.contains(index) else { return .ignored } + page = index + return .handled + } } /// An image loaded from a URL, with the alt text as its accessibility label @@ -358,6 +655,8 @@ struct RemoteImage: View { let src: String? let alt: String var fit = false + /// Off for images inside something that clips them, like the gallery mosaic. + var rounded = true @Environment(\.openUITheme) private var theme var body: some View { @@ -385,7 +684,7 @@ struct RemoteImage: View { .clipped() } } - .clipShape(RoundedRectangle(cornerRadius: theme.smallCornerRadius)) + .clipShape(RoundedRectangle(cornerRadius: rounded ? theme.smallCornerRadius : 0)) .accessibilityLabel(alt) } diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 065f512381..354e16d93b 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -453,3 +453,39 @@ let globalTestLibrary = SwiftUILibrary( == [.paragraph("See ![a](https://x.test/a.png) here")]) } } + +@Suite struct GalleryMosaicTests { + /// The frames tile the gallery like react-ui's grid templates: inside the + /// bounds, no overlaps, and the first image the largest. + @Test(arguments: [false, true], 1...5) + func tilesLikeReactUI(narrow: Bool, count: Int) { + let width: CGFloat = narrow ? 360 : 700 + let bounds = CGRect( + x: 0, y: 0, width: width, height: GalleryMosaic.height(width: width, count: count)) + let frames = GalleryMosaic.frames(count: count, in: bounds) + #expect(frames.count == count) + for (index, frame) in frames.enumerated() { + #expect(bounds.insetBy(dx: -0.5, dy: -0.5).contains(frame)) + for other in frames[(index + 1)...] { + #expect(frame.intersection(other).width < 0.5 || frame.intersection(other).height < 0.5) + } + #expect(frame.width * frame.height <= frames[0].width * frames[0].height + 0.5) + } + // Nothing left uncovered but the gaps. + let area = frames.reduce(0) { $0 + $1.width * $1.height } + #expect(area > bounds.width * bounds.height * 0.9) + } + + @Test func usesReactUITemplates() { + // Five or more, wide: 2fr 1fr 1fr with the first image down both rows. + let wide = GalleryMosaic.frames(count: 5, in: CGRect(x: 0, y: 0, width: 708, height: 376)) + #expect(wide[0] == CGRect(x: 0, y: 0, width: 346, height: 376)) + #expect(wide[1] == CGRect(x: 354, y: 0, width: 173, height: 184)) + #expect(wide[4] == CGRect(x: 535, y: 192, width: 173, height: 184)) + // Narrow: two on top, three below. + let narrow = GalleryMosaic.frames(count: 5, in: CGRect(x: 0, y: 0, width: 368, height: 288)) + #expect(narrow[0].width == narrow[1].width) + #expect(narrow[2].minY == narrow[3].minY && narrow[3].minY == narrow[4].minY) + #expect(GalleryMosaic.height(width: 1200, count: 5) == GalleryMosaic.maxHeight) + } +} From cb1cfce64b3a5b66d2f3c296bf9e0b26864ba7fd Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:19:39 +0530 Subject: [PATCH 24/52] docs(swift-lang): document theme colors, Cloud messages and transcripts Covers the theme's accent and chart palette, the OpenUI Cloud message helpers, the highlighter's limits, and laying out a chat transcript in a VStack: a LazyVStack re-measures rows inside animations (an animated scrollTo, the keyboard closing), which can block the main thread for seconds. --- packages/swift-lang/README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/swift-lang/README.md b/packages/swift-lang/README.md index 5cf9b8d7fc..35daabc827 100644 --- a/packages/swift-lang/README.md +++ b/packages/swift-lang/README.md @@ -105,6 +105,8 @@ struct MessageView: View { Pass the full response text so far on every chunk; the renderer only re-parses what changed. OpenUI Cloud responses wrap the program in `]]>openui:content` and `]]>openui:end` markers; pass them through as they are, like the JavaScript renderers do. +A finished response renders fully on its first frame, so a restored transcript doesn't flash empty rows. Lay a transcript out in a `VStack` inside the `ScrollView`, not a `LazyVStack`: a lazy stack re-measures rows as it goes, and when that happens inside an animation (an animated `scrollTo`, the keyboard closing) SwiftUI can block the main thread for seconds while response heights settle. + ## The chat library `OpenUIChatLibrary.library` renders every `openuiChatLibrary` component natively: cards and text, Markdown, callouts, code, images and galleries, Swift Charts (bar, line, area, horizontal bar, pie, radial, single stacked bar, scatter) and a radar chart, tables and the editable table, forms (inputs, text areas, selects, date pickers, sliders, check boxes, radios, switches, chips, option cards) with validation, buttons and icon buttons, lists and follow-ups, steps, tabs, accordions, sections, carousels, tags, entity lists and the card blocks. @@ -120,7 +122,7 @@ let prompt = OpenUIChatLibrary.library.prompt(ChatComponents.promptOptions) let systemMessage = try OpenUIChatLibrary.library.cloudConfig(ChatComponents.promptOptions) ``` -The views follow react-ui's layouts and behavior rather than restyling them: card blocks use the same responsive grid (one column on phones), tabs and sections follow the stream until the user picks one, charts use react-ui's palette and curves, and `[n]` citations resolve against the card's sources. Lucide icon names map to SF Symbols with the same category fallbacks. Spacing, fills and corner radii come from `OpenUITheme`, which follows react-ui's design tokens; override it with `.environment(\.openUITheme, theme)`. +The views follow react-ui's layouts and behavior rather than restyling them: card blocks use the same responsive grid (one column on phones), tabs and sections follow the stream until the user picks one, charts use react-ui's palette and curves, and `[n]` citations resolve against the card's sources. Lucide icon names map to SF Symbols with the same category fallbacks. Spacing, fills and corner radii come from `OpenUITheme`, which follows react-ui's design tokens; override it with `.environment(\.openUITheme, theme)`. Its `accent` and `onAccent` color primary buttons, selections and steps (the renderer also tints controls with `accent`), and `chartPalette` replaces the default chart ramp, like react-ui's `defaultChartPalette`. The schemas in `ChatComponents` live in `OpenUILang`, without SwiftUI, so a Swift server can build the chat prompt too. They're generated from `openuiChatLibrary` (see [Testing Locally](#testing-locally)). @@ -181,6 +183,9 @@ Components read the renderer state from the environment: | `generateCloudConfig(library:promptOptions:instructions:)`, `library.cloudConfig(_:instructions:)` | OpenUI Cloud's config block (`generateSystemPrompt({ cloud: true })`). | | `mergeStatements(_:_:rootId:)` | Edit mode: applies a patch program to an existing one. | | `evaluate(_:_:)`, `Store`, `QueryManager` | Lower-level runtime pieces. | +| `separateContentAndContext(_:)`, `wrapContent(_:)`, `wrapContext(_:)`, `hasLangSyntax(_:)` | OpenUI Cloud's message format, from react-ui's `sentinelParser`: split a stored message into the program and its state. | +| `messageWithState(content:contentHeader:state:)`, `continueConversationMessage(_:)` | Build the messages react-ui sends back: a response with its form state, and a follow-up from an action. | +| `initialState(fromContext:)`, `parseArtifactSentinel(_:)` | Restore form state from a stored message, and read an `]]>openui:artifact` header. | ## Tool Provider Support (Queries & Mutations) @@ -209,6 +214,7 @@ Conform your own type to `ToolProvider` for MCP or other backends; `extractToolR - Composite values (arrays, objects) have no identity in Swift, so `==` between two of them is always false. In JavaScript it's true only for the same instance. - Prop evaluation and SwiftUI views can't throw, so `onError` never reports `runtime-error` or `render-error`. - `$$` math in text content shows as source; there's no native TeX renderer. +- Code is highlighted with Prism's `vscDarkPlus` and `oneLight` colors by a small built-in tokenizer covering common languages (C-family, JSON, markup, Python, Ruby, shell, YAML, SQL), not by Prism's grammars. - Not ported: `jsonToOpenUI`, the deprecated `enrichErrors` (its hints are in `onError`), and the server-side `artifactTool` from `@openuidev/lang-core/cloud`. ## Testing Locally @@ -221,7 +227,7 @@ swift test swift format lint --strict -r Sources Tests Package.swift ``` -The conformance fixtures in `Tests/OpenUILangTests/Fixtures` are generated from the TypeScript packages, which are the source of truth. They cover batch and streaming parsing, prop evaluation, prompts, OpenUI Cloud config, edit-mode merging, error hints and the chat library schemas. After changing `lang-core` or the chat library, rebuild and regenerate them, and regenerate `ChatComponents.swift` when the chat library changed: +The conformance fixtures in `Tests/OpenUILangTests/Fixtures` are generated from the TypeScript packages, which are the source of truth. They cover batch and streaming parsing, prop evaluation, prompts, OpenUI Cloud config, edit-mode merging, error hints, OpenUI Cloud's message format and the chat library schemas. After changing `lang-core`, the chat library or react-ui's `sentinelParser`, rebuild and regenerate them (the script imports react-ui's TypeScript source directly, so it needs Node 22.18 or newer), and regenerate `ChatComponents.swift` when the chat library changed: ```bash pnpm run build:packages From 7e166b4f9f5c8251a3dd2c71bb6d0e74a794b950 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:20:37 +0530 Subject: [PATCH 25/52] ci: run the Swift checks when react-ui's sentinelParser changes The message fixtures are generated from sentinelParser.ts, so a change there can make them stale without touching the paths the workflow watched. --- .github/workflows/build-swift.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-swift.yml b/.github/workflows/build-swift.yml index 326daf307c..dbce762d0c 100644 --- a/.github/workflows/build-swift.yml +++ b/.github/workflows/build-swift.yml @@ -7,6 +7,7 @@ on: - "packages/swift-lang/**" - "packages/lang-core/src/**" - "packages/react-ui/src/genui-lib/**" + - "packages/react-ui/src/utils/sentinelParser.ts" - ".github/workflows/build-swift.yml" pull_request: branches: [main] @@ -14,6 +15,7 @@ on: - "packages/swift-lang/**" - "packages/lang-core/src/**" - "packages/react-ui/src/genui-lib/**" + - "packages/react-ui/src/utils/sentinelParser.ts" - ".github/workflows/build-swift.yml" permissions: From 5d049c204307d473807ee1fce0859ee8d8dabc76 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:57:24 +0530 Subject: [PATCH 26/52] feat(swift-lang): add react-ui's chart tooltips and legends - Hovering with a pointer or tapping shows react-ui's tooltip, with each visible series' value in its tooltip number format, and its crosshair: a band behind bars, a dashed line with dots on lines and areas. A tap rather than a drag picks, so a chart never takes over scrolling. Tapping the same category closes it, and opening another closes it. - Legends are react-ui's DefaultLegend: centered keys that fold behind "N more" when they don't fit on one line. Tapping a key hides that series, never the last one, and colors stay put. - Value axes sit on the leading side with react-ui's tick format (1.3K, 2.5M). Axis titles go above and below the plot, as in react-ui's condensed charts, instead of inside it, where an empty one still took room. Fixes found on the way: pie and radial slices are sorted largest first, as react-ui sorts them, and the single stacked bar now matches react-ui's SegmentedBar (ramp colors in input order, a 20pt track with gaps, shares in the legend, a value and share tooltip). The number format fixtures come from react-ui's formatters, so the Swift workflow also runs when those change. --- .github/workflows/build-swift.yml | 4 + packages/swift-lang/README.md | 4 +- .../swift-lang/Scripts/generate-fixtures.mjs | 45 +- .../Components/ChartComponents.swift | 516 ++++++++++++++---- .../Components/ChartInteraction.swift | 459 ++++++++++++++++ .../Sources/OpenUISwiftUI/OpenUIContext.swift | 4 + .../Sources/OpenUISwiftUI/Support.swift | 4 +- .../Fixtures/chart-formats.json | 147 +++++ .../OpenUISwiftUITests/RendererTests.swift | 101 ++++ 9 files changed, 1162 insertions(+), 122 deletions(-) create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartInteraction.swift create mode 100644 packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chart-formats.json diff --git a/.github/workflows/build-swift.yml b/.github/workflows/build-swift.yml index dbce762d0c..4ab495cd4f 100644 --- a/.github/workflows/build-swift.yml +++ b/.github/workflows/build-swift.yml @@ -8,6 +8,8 @@ on: - "packages/lang-core/src/**" - "packages/react-ui/src/genui-lib/**" - "packages/react-ui/src/utils/sentinelParser.ts" + - "packages/react-ui/src/components/Charts/utils/styleUtils.ts" + - "packages/react-ui/src/components/Charts/shared/core/PortalTooltip/utils/**" - ".github/workflows/build-swift.yml" pull_request: branches: [main] @@ -16,6 +18,8 @@ on: - "packages/lang-core/src/**" - "packages/react-ui/src/genui-lib/**" - "packages/react-ui/src/utils/sentinelParser.ts" + - "packages/react-ui/src/components/Charts/utils/styleUtils.ts" + - "packages/react-ui/src/components/Charts/shared/core/PortalTooltip/utils/**" - ".github/workflows/build-swift.yml" permissions: diff --git a/packages/swift-lang/README.md b/packages/swift-lang/README.md index 35daabc827..528bc43b3c 100644 --- a/packages/swift-lang/README.md +++ b/packages/swift-lang/README.md @@ -122,7 +122,7 @@ let prompt = OpenUIChatLibrary.library.prompt(ChatComponents.promptOptions) let systemMessage = try OpenUIChatLibrary.library.cloudConfig(ChatComponents.promptOptions) ``` -The views follow react-ui's layouts and behavior rather than restyling them: card blocks use the same responsive grid (one column on phones), tabs and sections follow the stream until the user picks one, charts use react-ui's palette and curves, and `[n]` citations resolve against the card's sources. Lucide icon names map to SF Symbols with the same category fallbacks. Spacing, fills and corner radii come from `OpenUITheme`, which follows react-ui's design tokens; override it with `.environment(\.openUITheme, theme)`. Its `accent` and `onAccent` color primary buttons, selections and steps (the renderer also tints controls with `accent`), and `chartPalette` replaces the default chart ramp, like react-ui's `defaultChartPalette`. +The views follow react-ui's layouts and behavior rather than restyling them: card blocks use the same responsive grid (one column on phones), tabs and sections follow the stream until the user picks one, charts use react-ui's palette, curves and number formats, with its legends (tap a key to hide that series) and tooltips (hover with a pointer, or tap), and `[n]` citations resolve against the card's sources. Lucide icon names map to SF Symbols with the same category fallbacks. Spacing, fills and corner radii come from `OpenUITheme`, which follows react-ui's design tokens; override it with `.environment(\.openUITheme, theme)`. Its `accent` and `onAccent` color primary buttons, selections and steps (the renderer also tints controls with `accent`), and `chartPalette` replaces the default chart ramp, like react-ui's `defaultChartPalette`. The schemas in `ChatComponents` live in `OpenUILang`, without SwiftUI, so a Swift server can build the chat prompt too. They're generated from `openuiChatLibrary` (see [Testing Locally](#testing-locally)). @@ -227,7 +227,7 @@ swift test swift format lint --strict -r Sources Tests Package.swift ``` -The conformance fixtures in `Tests/OpenUILangTests/Fixtures` are generated from the TypeScript packages, which are the source of truth. They cover batch and streaming parsing, prop evaluation, prompts, OpenUI Cloud config, edit-mode merging, error hints, OpenUI Cloud's message format and the chat library schemas. After changing `lang-core`, the chat library or react-ui's `sentinelParser`, rebuild and regenerate them (the script imports react-ui's TypeScript source directly, so it needs Node 22.18 or newer), and regenerate `ChatComponents.swift` when the chat library changed: +The conformance fixtures in `Tests/OpenUILangTests/Fixtures` are generated from the TypeScript packages, which are the source of truth. They cover batch and streaming parsing, prop evaluation, prompts, OpenUI Cloud config, edit-mode merging, error hints, OpenUI Cloud's message format, the chart number formats and the chat library schemas. After changing `lang-core`, the chat library, react-ui's `sentinelParser` or its chart formatters, rebuild and regenerate them (the script imports react-ui's TypeScript source directly, so it needs Node 22.18 or newer), and regenerate `ChatComponents.swift` when the chat library changed: ```bash pnpm run build:packages diff --git a/packages/swift-lang/Scripts/generate-fixtures.mjs b/packages/swift-lang/Scripts/generate-fixtures.mjs index 08ec467fc6..64ed0d8bbf 100644 --- a/packages/swift-lang/Scripts/generate-fixtures.mjs +++ b/packages/swift-lang/Scripts/generate-fixtures.mjs @@ -649,10 +649,13 @@ const messageInputs = [ ["empty", ""], ["plain text", "Just some text"], ["content only", "]]>openui:content\nroot = Card([])"], - ["content with header attrs", "]]>openui:content?thesys=true&libraryVersion=0.1.0\nroot = Card([])"], + [ + "content with header attrs", + "]]>openui:content?thesys=true&libraryVersion=0.1.0\nroot = Card([])", + ], ["content and context", ']]>openui:content\nroot = Card([])\n]]>openui:context\n[{"f":1}]'], ["context only", 'Hello\n]]>openui:context\n["User clicked: Go"]'], - ["context then content", ']]>openui:context\n[1]\n]]>openui:content\nroot = X()'], + ["context then content", "]]>openui:context\n[1]\n]]>openui:content\nroot = X()"], ["last content wins", "]]>openui:content\nold\n]]>openui:content\nnew"], ["crlf separators", "]]>openui:content\r\nroot = X()\r\n]]>openui:context\r\n[1]"], ["end marker", "]]>openui:content\nroot = X()\n]]>openui:end"], @@ -668,7 +671,7 @@ const messageInputs = [ ["bracket that isn't a marker", "]]>openui:content\nx = [1, 2]"], ["marker header without newline", "]]>openui:content"], ["markers on one line", "]]>openui:content]]>openui:context\n[1]"], - ["emoji", "]]>openui:content\nroot = TextContent(\"🙂 hi\")\n]]>openui:context\n[\"🎉\"]"], + ["emoji", ']]>openui:content\nroot = TextContent("🙂 hi")\n]]>openui:context\n["🎉"]'], ["legacy xml", 'root = X()\n[{"a":1}]'], ["legacy content only", "root = X() "], ["legacy context only", 'text\n["x"]\n'], @@ -716,12 +719,40 @@ const messageCases = { })), wrap: { content: sentinel.wrapContent("root = X()"), - contentWithHeader: sentinel.wrapContentWithHeader("root = X()", "]]>openui:content?thesys=true"), + contentWithHeader: sentinel.wrapContentWithHeader( + "root = X()", + "]]>openui:content?thesys=true", + ), contentWithoutHeader: sentinel.wrapContentWithHeader("root = X()", undefined), context: sentinel.wrapContext('[{"a":1}]'), }, }; +// ── Chart number formats ───────────────────────────────────────────────── +// +// react-ui's axis and tooltip formatters, imported from source like +// sentinelParser. toLocaleString follows the machine's locale, so it's pinned +// to en-US here; the Swift tests format with the same locale. + +const charts = join(packages, "react-ui", "src", "components", "Charts"); +const { numberTickFormatter } = await import(join(charts, "utils", "styleUtils.ts")); +const { tooltipNumberFormatter } = await import( + join(charts, "shared", "core", "PortalTooltip", "utils", "index.ts") +); +const toLocaleString = Number.prototype.toLocaleString; +Number.prototype.toLocaleString = function (locales, options) { + return toLocaleString.call(this, locales ?? "en-US", options); +}; +const chartFormatCases = [ + 0, 1, -1, 7, 0.5, 0.125, 1.005, 1.25, 12.345, -0.04, 0.005, 999, 999.99, 1000, 1250, 9999, 10000, + 15500, -2500, 99999.5, 100000, 123456, 999999, 1234567, -7654321, 2.5e9, 1e12, 15e12, 1.23456, +].map((value) => ({ + value, + tick: numberTickFormatter(value), + tooltip: tooltipNumberFormatter(value), +})); +Number.prototype.toLocaleString = toLocaleString; + function write(name, data, indent = 1) { mkdirSync(fixtures, { recursive: true }); writeFileSync(join(fixtures, name), JSON.stringify(data, null, indent) + "\n"); @@ -749,7 +780,11 @@ writeFileSync( ) + "\n", ); write("chat-spec.json", chatComponentSpecs); +writeFileSync( + join(here, "..", "Tests", "OpenUISwiftUITests", "Fixtures", "chart-formats.json"), + JSON.stringify(chartFormatCases, null, 1) + "\n", +); console.log( - `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set, ${evalFixtures.length} evaluation, ${promptCases.length} prompt, ${mergeCases.length} merge, ${errorCases.length} error, ${cloudCases.length} cloud, ${messageCases.separate.length} message fixtures`, + `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set, ${evalFixtures.length} evaluation, ${promptCases.length} prompt, ${mergeCases.length} merge, ${errorCases.length} error, ${cloudCases.length} cloud, ${messageCases.separate.length} message, ${chartFormatCases.length} chart format fixtures`, ); diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift index 859b151f8e..98d86f9cac 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift @@ -78,28 +78,44 @@ enum ChartPalette { } } -/// Series names in order, for the color scale. +/// Series names in order. private func seriesNames(_ props: ComponentProps) -> [String] { var seen: Set = [] return props.children("series").map { $0.text("category") }.filter { seen.insert($0).inserted } } -/// Colors chart series with the theme's palette. -private struct PaletteScale: ViewModifier { +/// A chart's series and their colors. Colors are assigned over every series, +/// so hiding one from the legend doesn't recolor the rest. +private struct SeriesColors { let names: [String] - @Environment(\.openUITheme) private var theme + let colors: [Color] + + init(_ names: [String], _ palette: [Color]?) { + self.names = names + colors = ChartPalette.colors(names.count, palette) + } - func body(content: Content) -> some View { - content.chartForegroundStyleScale( - domain: names, range: ChartPalette.colors(names.count, theme.chartPalette)) + func color(_ name: String) -> Color { + names.firstIndex(of: name).map { colors[$0] } ?? .gray + } + + var legend: [LegendEntry] { + zip(names, colors).map { LegendEntry(id: $0, label: $0, color: $1) } } } -extension View { - fileprivate func paletteScale(_ names: [String]) -> some View { - modifier(PaletteScale(names: names)) +/// The tooltip for one category: each visible series' value there. +private func seriesTooltip( + _ label: String, _ points: [SeriesPoint], _ series: SeriesColors +) -> ChartTooltipContent? { + let items = points.filter { $0.label == label }.map { + ChartTooltipContent.Item( + name: $0.series, value: ChartFormat.tooltip($0.value), color: series.color($0.series)) } + return items.isEmpty ? nil : ChartTooltipContent(label: label, items: items) +} +extension View { /// Horizontal grid lines only, as react-ui's cartesian charts draw them. fileprivate func categoryAxisWithoutGrid() -> some View { chartXAxis { @@ -109,20 +125,41 @@ extension View { } } } + + /// react-ui's value axis: on the leading side, with grid lines and its tick + /// format (1.3K, 2.5M). + fileprivate func valueAxis(_ axis: Axis = .vertical) -> some View { + let marks = AxisMarks(position: axis == .vertical ? .leading : .bottom) { value in + AxisGridLine() + AxisValueLabel { + if let number = value.as(Double.self) { Text(ChartFormat.tick(number)) } + } + } + return Group { + if axis == .vertical { chartYAxis { marks } } else { chartXAxis { marks } } + } + } } -/// Sizes a chart, puts its legend below, and shows a pulsing placeholder -/// while the response streams in before any of its values have. +/// Sizes a chart and puts react-ui's legend under it, or shows a pulsing +/// placeholder while the response streams in before any of its values have. private struct ChartFrame: View { let props: ComponentProps let isEmpty: Bool + let legend: [LegendEntry] + let hidden: Binding>? let content: Content @Environment(OpenUIContext.self) private var context @Environment(\.openUITheme) private var theme - init(_ props: ComponentProps, isEmpty: Bool, @ViewBuilder content: () -> Content) { + init( + _ props: ComponentProps, isEmpty: Bool, legend: [LegendEntry], + hidden: Binding>? = nil, @ViewBuilder content: () -> Content + ) { self.props = props self.isEmpty = isEmpty + self.legend = legend + self.hidden = hidden self.content = content() } @@ -131,20 +168,59 @@ private struct ChartFrame: View { if isEmpty && (context.isStreaming || context.isQueryLoading) { SkeletonBlock(height: height, cornerRadius: 8) } else { + VStack(spacing: 12) { + AxisTitles(props) { + content + .frame(height: height) + .chartLegend(.hidden) + } + if !legend.isEmpty { ChartLegend(entries: legend, hidden: hidden) } + } + } + } +} + +/// react-ui's condensed charts put the axis titles outside the plot: the y +/// title above it, the x title centered below. Outside the chart, a missing +/// title takes no room (Swift Charts keeps room for an empty one), and one +/// that streams in after the data doesn't rebuild the chart. +private struct AxisTitles: View { + let x: String + let y: String + let content: Content + + init(_ props: ComponentProps, @ViewBuilder content: () -> Content) { + x = props.text("xLabel") + y = props.text("yLabel") + self.content = content() + } + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + if !y.isEmpty { + Text(y).font(.caption).foregroundStyle(.secondary).padding(.bottom, 8) + } content - .frame(height: height) - .chartLegend(position: .bottom, alignment: .leading) + if !x.isEmpty { + Text(x).font(.caption).foregroundStyle(.secondary).frame(maxWidth: .infinity) + } } } } struct BarChartView: View { let props: ComponentProps + @State private var hidden: Set = [] + @State private var selection: ChartSelection? + @Environment(\.openUITheme) private var theme var body: some View { - let points = seriesPoints(props) + let all = seriesPoints(props) + let points = all.filter { !hidden.contains($0.series) } + let series = SeriesColors(seriesNames(props), theme.chartPalette) + let labels = labelOrder(props) let stacked = props.string("variant") == "stacked" - ChartFrame(props, isEmpty: points.isEmpty) { + ChartFrame(props, isEmpty: all.isEmpty, legend: series.legend, hidden: $hidden) { Chart(points) { point in if stacked { BarMark(x: .value("Label", point.label), y: .value("Value", point.value)) @@ -156,11 +232,17 @@ struct BarChartView: View { .cornerRadius(4) } } - .chartXScale(domain: labelOrder(props)) - .paletteScale(seriesNames(props)) + .chartXScale(domain: labels) + .chartForegroundStyleScale(domain: series.names, range: series.colors) .categoryAxisWithoutGrid() - .chartXAxisLabel(props.text("xLabel")) - .chartYAxisLabel(props.text("yLabel")) + .valueAxis() + .categoryPicker( + $selection, crosshairBehind: true, tooltip: { seriesTooltip($0, points, series) } + ) { proxy, plot, label in + if let x = proxy.position(forX: label) { + BandHighlight(center: x, slot: plot.width / CGFloat(max(labels.count, 1)), plot: plot) + } + } .chartEntrance(.grow) .openUIAnimation(Motion.dataMorph, value: points) } @@ -169,12 +251,17 @@ struct BarChartView: View { struct HorizontalBarChartView: View { let props: ComponentProps + @State private var hidden: Set = [] + @State private var selection: ChartSelection? + @Environment(\.openUITheme) private var theme var body: some View { - let points = seriesPoints(props) + let all = seriesPoints(props) + let points = all.filter { !hidden.contains($0.series) } + let series = SeriesColors(seriesNames(props), theme.chartPalette) let stacked = props.string("variant") == "stacked" let labels = labelOrder(props) - ChartFrame(props, isEmpty: points.isEmpty) { + ChartFrame(props, isEmpty: all.isEmpty, legend: series.legend, hidden: $hidden) { Chart(points) { point in if stacked { BarMark( @@ -191,15 +278,24 @@ struct HorizontalBarChartView: View { } } .chartYScale(domain: labels) - .paletteScale(seriesNames(props)) + .chartForegroundStyleScale(domain: series.names, range: series.colors) .chartYAxis { AxisMarks(preset: .aligned, position: .leading) { _ in AxisValueLabel(horizontalSpacing: 8) } } + .valueAxis(.horizontal) .frame(minHeight: CGFloat(labels.count) * 28) - .chartXAxisLabel(props.text("xLabel")) - .chartYAxisLabel(props.text("yLabel")) + .categoryPicker( + $selection, axis: .vertical, crosshairBehind: true, + tooltip: { seriesTooltip($0, points, series) } + ) { proxy, plot, label in + if let y = proxy.position(forY: label) { + BandHighlight( + center: y, slot: plot.height / CGFloat(max(labels.count, 1)), plot: plot, + axis: .vertical) + } + } .chartEntrance(.growSideways) .openUIAnimation(Motion.dataMorph, value: points) } @@ -208,11 +304,16 @@ struct HorizontalBarChartView: View { struct LineChartView: View { let props: ComponentProps + @State private var hidden: Set = [] + @State private var selection: ChartSelection? + @Environment(\.openUITheme) private var theme var body: some View { let method = interpolation(props.string("variant")) - let points = seriesPoints(props) - ChartFrame(props, isEmpty: points.isEmpty) { + let all = seriesPoints(props) + let points = all.filter { !hidden.contains($0.series) } + let series = SeriesColors(seriesNames(props), theme.chartPalette) + ChartFrame(props, isEmpty: all.isEmpty, legend: series.legend, hidden: $hidden) { Chart(points) { point in LineMark(x: .value("Label", point.label), y: .value("Value", point.value)) .foregroundStyle(by: .value("Series", point.series)) @@ -220,28 +321,47 @@ struct LineChartView: View { .lineStyle(StrokeStyle(lineWidth: 2)) } .chartXScale(domain: labelOrder(props)) - .paletteScale(seriesNames(props)) + .chartForegroundStyleScale(domain: series.names, range: series.colors) .categoryAxisWithoutGrid() + .valueAxis() + .categoryPicker($selection, tooltip: { seriesTooltip($0, points, series) }) { + proxy, plot, label in + lineCrosshair(proxy, plot, label, points, series) + } .chartEntrance(.draw) .openUIAnimation(Motion.dataMorph, value: points) - .chartXAxisLabel(props.text("xLabel")) - .chartYAxisLabel(props.text("yLabel")) } } } +@ViewBuilder +private func lineCrosshair( + _ proxy: ChartProxy, _ plot: CGRect, _ label: String, _ points: [SeriesPoint], + _ series: SeriesColors +) -> some View { + if let x = proxy.position(forX: label) { + LineCrosshair( + x: x, plot: plot, + dots: points.filter { $0.label == label }.compactMap { point in + proxy.position(forY: point.value).map { (y: $0, color: series.color(point.series)) } + }) + } +} + struct AreaChartView: View { let props: ComponentProps + @State private var hidden: Set = [] + @State private var selection: ChartSelection? @Environment(\.openUITheme) private var theme var body: some View { let method = interpolation(props.string("variant")) - let names = seriesNames(props) - let colors = ChartPalette.colors(names.count, theme.chartPalette) - let points = seriesPoints(props) - ChartFrame(props, isEmpty: points.isEmpty) { + let series = SeriesColors(seriesNames(props), theme.chartPalette) + let all = seriesPoints(props) + let points = all.filter { !hidden.contains($0.series) } + ChartFrame(props, isEmpty: all.isEmpty, legend: series.legend, hidden: $hidden) { Chart(points) { point in - let color = colors[names.firstIndex(of: point.series) ?? 0] + let color = series.color(point.series) // react-ui fills areas with a gradient from 60% opacity to clear. AreaMark( x: .value("Label", point.label), y: .value("Value", point.value), @@ -258,18 +378,21 @@ struct AreaChartView: View { .lineStyle(StrokeStyle(lineWidth: 2)) } .chartXScale(domain: labelOrder(props)) - .chartForegroundStyleScale(domain: names, range: colors) + .chartForegroundStyleScale(domain: series.names, range: series.colors) .categoryAxisWithoutGrid() + .valueAxis() + .categoryPicker($selection, tooltip: { seriesTooltip($0, points, series) }) { + proxy, plot, label in + lineCrosshair(proxy, plot, label, points, series) + } .chartEntrance(.draw) .openUIAnimation(Motion.dataMorph, value: points) - .chartXAxisLabel(props.text("xLabel")) - .chartYAxisLabel(props.text("yLabel")) } } } /// One labelled value of a 1D chart. -private struct Slice: Identifiable, Equatable { +struct Slice: Identifiable, Equatable { let id: Int let label: String let value: Double @@ -285,105 +408,268 @@ private func slices(_ props: ComponentProps) -> [Slice] { } } +/// Pie and radial slices as react-ui orders them: largest first (a stable +/// sort, like JavaScript's), each with its color from the middle of the ramp +/// outwards in that order. +func sortedSlices(_ slices: [Slice], _ palette: [Color]?) -> [(slice: Slice, color: Color)] { + let sorted = slices.enumerated().sorted { + $0.element.value != $1.element.value + ? $0.element.value > $1.element.value : $0.offset < $1.offset + }.map(\.element) + return Array(zip(sorted, ChartPalette.colors(sorted.count, palette))) +} + +/// Where pie slices are: Swift Charts starts at 12 o'clock and goes clockwise, +/// with the radius half the shorter side. +enum PieGeometry { + /// The index of the slice under `point`, or nil outside the ring. A + /// semicircle is drawn turned a quarter to the left, so its angles are too. + static func slice( + at point: CGPoint, in size: CGSize, values: [Double], innerRatio: CGFloat, semicircle: Bool + ) -> Int? { + let dx = point.x - size.width / 2 + let dy = point.y - size.height / 2 + let radius = min(size.width, size.height) / 2 + let distance = (dx * dx + dy * dy).squareRoot() + guard distance <= radius, distance >= radius * innerRatio else { return nil } + var angle = atan2(Double(dx), Double(-dy)) + (semicircle ? Double.pi / 2 : 0) + angle = angle.truncatingRemainder(dividingBy: 2 * .pi) + if angle < 0 { angle += 2 * .pi } + let total = values.reduce(0, +) * (semicircle ? 2 : 1) + guard total > 0 else { return nil } + var end = 0.0 + for (index, value) in values.enumerated() { + end += value / total * 2 * .pi + if angle < end { return index } + } + return nil + } +} + struct PieChartView: View { let props: ComponentProps + @State private var hidden: Set = [] + @State private var selection: ChartSelection? + @State private var legendHover: String? @Environment(\.openUITheme) private var theme var body: some View { - let data = slices(props) + let all = sortedSlices(slices(props), theme.chartPalette) + let visible = all.filter { !hidden.contains(String($0.slice.id)) } let donut = props.string("variant") == "donut" let semi = props.string("appearance") == "semiCircular" - let total = data.reduce(0) { $0 + $1.value } - Chart { - ForEach(data) { slice in - SectorMark( - angle: .value("Value", slice.value), innerRadius: .ratio(donut ? 0.6 : 0), - angularInset: 1 - ) - .foregroundStyle(by: .value("Label", slice.label)) + let total = visible.reduce(0) { $0 + $1.slice.value } + let active = selection?.key ?? legendHover + VStack(spacing: 12) { + Chart { + ForEach(visible, id: \.slice.id) { slice, color in + SectorMark( + angle: .value("Value", slice.value), innerRadius: .ratio(donut ? 0.6 : 0), + angularInset: 1 + ) + .foregroundStyle(color) + .opacity(active == nil || active == String(slice.id) ? 1 : 0.4) + .accessibilityLabel(slice.label) + .accessibilityValue(ChartFormat.tooltip(slice.value)) + } + if semi, total > 0 { + // A transparent half that keeps the visible slices on the top half. + SectorMark(angle: .value("Value", total), innerRadius: .ratio(donut ? 0.6 : 0)) + .foregroundStyle(.clear) + } } - if semi, total > 0 { - // A transparent half that keeps the visible slices on the top half. - SectorMark(angle: .value("Value", total), innerRadius: .ratio(donut ? 0.6 : 0)) - .foregroundStyle(.clear) + .rotationEffect(semi ? .degrees(-90) : .zero) + .overlay { + GeometryReader { geometry in + ZStack(alignment: .topLeading) { + PickSurface(selection: $selection) { point in + PieGeometry.slice( + at: point, in: geometry.size, values: visible.map(\.slice.value), + innerRatio: donut ? 0.6 : 0, semicircle: semi + ).map { String(visible[$0].slice.id) } + } + if let key = selection?.key, let anchor = selection?.location, + let (slice, color) = visible.first(where: { String($0.slice.id) == key }) + { + TooltipPlacement(anchor: anchor) { + ChartTooltip( + content: ChartTooltipContent( + label: slice.label, + items: [ + .init( + name: slice.label, value: ChartFormat.tooltip(slice.value), color: color) + ] + )) + } + .allowsHitTesting(false) + } + } + } } + .frame(height: theme.chartHeight) + .openUIAnimation(Motion.dataMorph, value: visible.map(\.slice)) + .fadeAppear() + ChartLegend( + entries: all.map { + LegendEntry(id: String($0.slice.id), label: $0.slice.label, color: $0.color) + }, + hidden: $hidden, highlighted: $legendHover) } - .chartForegroundStyleScale( - domain: data.map(\.label), range: ChartPalette.colors(data.count, theme.chartPalette) - ) - .chartLegend(position: .bottom, alignment: .leading) - .rotationEffect(semi ? .degrees(-90) : .zero) - .frame(height: theme.chartHeight) - .openUIAnimation(Motion.dataMorph, value: data) - .fadeAppear() } } struct RadialChartView: View { let props: ComponentProps + @State private var hidden: Set = [] @Environment(\.openUITheme) private var theme var body: some View { - let data = slices(props) - let colors = ChartPalette.colors(props.array("values").count, theme.chartPalette) - let maximum = max(data.map(\.value).max() ?? 1, 1) - HStack(spacing: theme.spacing) { + let all = sortedSlices(slices(props), theme.chartPalette) + let visible = all.filter { !hidden.contains(String($0.slice.id)) } + let maximum = max(visible.map(\.slice.value).max() ?? 1, 1) + VStack(spacing: 12) { ZStack { - ForEach(data) { slice in - let inset = CGFloat(slice.id) * 14 + ForEach(Array(visible.enumerated()), id: \.element.slice.id) { ring, entry in + let inset = CGFloat(ring) * 14 Circle() .stroke(.secondary.opacity(0.15), lineWidth: 10) .padding(inset) Circle() - .trim(from: 0, to: slice.value / maximum * 0.75) - .stroke(colors[slice.id], style: StrokeStyle(lineWidth: 10, lineCap: .round)) + .trim(from: 0, to: entry.slice.value / maximum * 0.75) + .stroke(entry.color, style: StrokeStyle(lineWidth: 10, lineCap: .round)) .rotationEffect(.degrees(-90)) .padding(inset) + .accessibilityElement() + .accessibilityLabel(entry.slice.label) + .accessibilityValue(jsNumberToString(entry.slice.value)) } } .frame(width: theme.chartHeight * 0.8, height: theme.chartHeight * 0.8) - VStack(alignment: .leading, spacing: 4) { - ForEach(data) { slice in - HStack(spacing: 6) { - Circle().fill(colors[slice.id]).frame(width: 8, height: 8) - Text(slice.label).font(.caption) - Text(jsNumberToString(slice.value)).font(.caption.monospacedDigit()) - .foregroundStyle(.secondary) - } - } - } + .frame(maxWidth: .infinity) + ChartLegend( + entries: all.map { + LegendEntry(id: String($0.slice.id), label: $0.slice.label, color: $0.color) + }, + hidden: $hidden) } - .openUIAnimation(Motion.dataMorph, value: data) + .openUIAnimation(Motion.dataMorph, value: visible.map(\.slice)) .fadeAppear() } } +/// react-ui's SingleStackedBar (its SegmentedBar): one rounded track split by +/// share, colored down the ramp in the given order, with each segment's share +/// in the legend. Hovering or tapping a segment (or its key) dims the rest +/// and shows its value and share. struct SingleStackedBarChartView: View { let props: ComponentProps + @State private var selection: ChartSelection? + @State private var legendHover: String? @Environment(\.openUITheme) private var theme var body: some View { let data = slices(props) - Chart(data) { slice in - BarMark(x: .value("Value", slice.value), y: .value("Total", "")) - .foregroundStyle(by: .value("Label", slice.label)) + let ramp = theme.chartPalette.flatMap { $0.isEmpty ? nil : $0 } ?? ChartPalette.ocean + let total = data.reduce(0) { $0 + $1.value } + let share = { (slice: Slice) in total > 0 ? slice.value / total : 0 } + let color = { (slice: Slice) in ramp[slice.id % ramp.count] } + let active = selection?.key ?? legendHover + VStack(spacing: 12) { + SegmentRow(shares: data.map(share)) { + ForEach(data) { slice in + Rectangle() + .fill(color(slice)) + .opacity(active == nil || active == String(slice.id) ? 1 : 0.4) + .accessibilityElement() + .accessibilityLabel(slice.label) + .accessibilityValue(ChartFormat.toFixed(share(slice) * 100, 1) + "%") + } + } + .frame(height: 20) + .clipShape(RoundedRectangle(cornerRadius: 6)) + .overlay { + GeometryReader { geometry in + ZStack(alignment: .topLeading) { + PickSurface(selection: $selection) { point in + SegmentRow.index(at: point.x, width: geometry.size.width, shares: data.map(share)) + .map { String(data[$0].id) } + } + if let key = selection?.key, let anchor = selection?.location, + let slice = data.first(where: { String($0.id) == key }) + { + TooltipPlacement(anchor: anchor, placement: .above) { + ChartTooltip( + content: ChartTooltipContent( + label: slice.label, + items: [ + .init( + name: "Value", value: ChartFormat.tick(slice.value), color: color(slice)), + .init( + name: "Percentage", value: ChartFormat.toFixed(share(slice) * 100, 1) + "%", + color: color(slice)), + ])) + } + .allowsHitTesting(false) + } + } + } + } + .openUIAnimation(Motion.dataMorph, value: data) + .chartEntrance(.growSideways) + ChartLegend( + entries: data.map { + LegendEntry( + id: String($0.id), label: $0.label, color: color($0), percentage: share($0) * 100) + }, + highlighted: $legendHover) } - .chartForegroundStyleScale( - domain: data.map(\.label), range: ChartPalette.colors(data.count, theme.chartPalette) - ) - .chartYAxis(.hidden) - .chartLegend(position: .bottom, alignment: .leading) - .frame(height: 80) - .openUIAnimation(Motion.dataMorph, value: data) - .chartEntrance(.growSideways) + } +} + +/// Lays segments out side by side, each as wide as its share of the row, +/// with react-ui's 2pt gaps. +struct SegmentRow: Layout { + let shares: [Double] + static let gap: CGFloat = 2 + + func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize { + proposal.replacingUnspecifiedDimensions() + } + + func placeSubviews( + in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout () + ) { + var x = bounds.minX + for (subview, width) in zip(subviews, Self.widths(bounds.width, shares)) { + subview.place( + at: CGPoint(x: x, y: bounds.minY), + proposal: ProposedViewSize(width: width, height: bounds.height)) + x += width + Self.gap + } + } + + static func widths(_ width: CGFloat, _ shares: [Double]) -> [CGFloat] { + let room = max(width - gap * CGFloat(max(shares.count - 1, 0)), 0) + return shares.map { room * CGFloat($0) } + } + + /// The segment at `x`, counting each gap with the segment before it. + static func index(at x: CGFloat, width: CGFloat, shares: [Double]) -> Int? { + var end: CGFloat = 0 + for (index, segment) in widths(width, shares).enumerated() { + end += segment + gap + if x < end, segment > 0 { return index } + } + return nil } } struct ScatterChartView: View { let props: ComponentProps + @State private var hidden: Set = [] @Environment(\.openUITheme) private var theme - private struct Dot: Identifiable { + private struct Dot: Identifiable, Equatable { let id: Int let series: String let x: Double @@ -400,22 +686,29 @@ struct ScatterChartView: View { Dot(id: dots.count, series: dataset.text("name"), x: x, y: y, z: point.number("z"))) } } - let names = props.children("datasets").map { $0.text("name") } - return Chart(dots) { dot in + let series = SeriesColors( + props.children("datasets").map { $0.text("name") }, theme.chartPalette) + let visible = dots.filter { !hidden.contains($0.series) } + return VStack(spacing: 12) { + AxisTitles(props) { + scatter(visible, all: dots, series: series) + } + ChartLegend(entries: series.legend, hidden: $hidden) + } + } + + private func scatter(_ visible: [Dot], all dots: [Dot], series: SeriesColors) -> some View { + Chart(visible) { dot in PointMark(x: .value(props.text("xLabel"), dot.x), y: .value(props.text("yLabel"), dot.y)) .foregroundStyle(by: .value("Series", dot.series)) .symbolSize(dot.z.map { max(20, min($0, 400)) } ?? 40) } .chartXScale(domain: Self.domain(dots.map(\.x))) .chartYScale(domain: Self.domain(dots.map(\.y))) - .chartForegroundStyleScale( - domain: names, range: ChartPalette.colors(names.count, theme.chartPalette) - ) - .chartXAxisLabel(props.text("xLabel")) - .chartYAxisLabel(props.text("yLabel")) - .chartLegend(position: .bottom, alignment: .leading) + .chartForegroundStyleScale(domain: series.names, range: series.colors) + .chartLegend(.hidden) .frame(height: theme.chartHeight) - .openUIAnimation(Motion.dataMorph, value: dots.map(\.x) + dots.map(\.y)) + .openUIAnimation(Motion.dataMorph, value: visible) .fadeAppear() } @@ -434,15 +727,18 @@ struct ScatterChartView: View { /// Charts has no radar mark, so it is drawn directly. struct RadarChartView: View { let props: ComponentProps + @State private var hidden: Set = [] @Environment(\.openUITheme) private var theme var body: some View { let labels = props.array("labels").map(displayText) - let series = props.children("series").map { series in + let all = props.children("series").map { series in (name: series.text("category"), values: series.array("values").map { $0.numberValue ?? 0 }) } + let colors = SeriesColors(all.map(\.name), theme.chartPalette) + let series = all.filter { !hidden.contains($0.name) } let maximum = max(series.flatMap(\.values).max() ?? 1, 1) - VStack(alignment: .leading, spacing: 8) { + VStack(spacing: 12) { Canvas { context, size in guard labels.count >= 3 else { return } let center = CGPoint(x: size.width / 2, y: size.height / 2) @@ -475,27 +771,19 @@ struct RadarChartView: View { context.draw( Text(labels[index]).font(.caption2).foregroundStyle(.secondary), at: point(index, 1.16)) } - for (index, entry) in series.enumerated() { + for entry in series { let fractions = labels.indices.map { $0 < entry.values.count ? entry.values[$0] / maximum : 0 } let shape = polygon(fractions) - let color = ChartPalette.colors(series.count, theme.chartPalette)[index] + let color = colors.color(entry.name) context.fill(shape, with: .color(color.opacity(0.18))) context.stroke(shape, with: .color(color), lineWidth: 2) } } .frame(height: theme.chartHeight + 40) .fadeAppear() - FlowLayout(spacing: 12) { - ForEach(Array(series.enumerated()), id: \.offset) { index, entry in - HStack(spacing: 6) { - Circle().fill(ChartPalette.colors(series.count, theme.chartPalette)[index]).frame( - width: 8, height: 8) - Text(entry.name).font(.caption).foregroundStyle(.secondary) - } - } - } + ChartLegend(entries: colors.legend, hidden: $hidden) } } } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartInteraction.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartInteraction.swift new file mode 100644 index 0000000000..02d654b8c1 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartInteraction.swift @@ -0,0 +1,459 @@ +import Charts +import OpenUILang +import SwiftUI + +// MARK: - Number formats + +/// The number formats react-ui's charts use. +enum ChartFormat { + /// `numberTickFormatter`, for value axes: 950, 1.3K, 16K, 2.5M; fractions + /// with two decimals. + static func tick(_ value: Double) -> String { + let magnitude = abs(value) + for (limit, suffix) in [(1e12, "T"), (1e9, "B"), (1e6, "M"), (1e3, "K")] + where magnitude >= limit { + return toFixed(value / limit, magnitude >= limit * 10 ? 0 : 1) + suffix + } + return value.truncatingRemainder(dividingBy: 1) != 0 + ? toFixed(value, 2) : jsNumberToString(value) + } + + /// `tooltipNumberFormatter`: grouped like `toLocaleString` below 100,000, + /// then 123.4K, 5.6M and so on, rounded down to one decimal. + static func tooltip(_ value: Double, locale: Locale = .current) -> String { + let sign = value < 0 ? "-" : "" + var scaled = abs(value) + if scaled < 100_000 { + return sign + + scaled.formatted( + .number.locale(locale).precision(.fractionLength(0...3)) + .rounded(rule: .toNearestOrAwayFromZero)) + } + let units = ["", "K", "M", "B", "T"] + var unit = 0 + while scaled >= 1000 && unit < units.count - 1 { + scaled /= 1000 + unit += 1 + } + return sign + jsNumberToString((scaled * 10).rounded(.down) / 10) + units[unit] + } + + /// JavaScript's `toFixed`. `printf` rounds a value exactly halfway between + /// two results to even; JavaScript rounds it away from zero (0.125 → "0.13"). + static func toFixed(_ value: Double, _ digits: Int) -> String { + let scale = pow(10, Double(digits)) + let scaled = abs(value) * scale + if scaled.truncatingRemainder(dividingBy: 1) == 0.5, scaled / scale == abs(value) { + let rounded = scaled.rounded(.awayFromZero) / scale + return String(format: "%.\(digits)f", value < 0 ? -rounded : rounded) + } + return String(format: "%.\(digits)f", value) + } +} + +// MARK: - Legend + +/// One key of a chart legend. +struct LegendEntry: Identifiable, Equatable { + let id: String + let label: String + let color: Color + var percentage: Double? +} + +/// react-ui's DefaultLegend: centered color keys under a chart. With +/// `hidden`, tapping a key hides its series (one always stays visible); with +/// `highlighted`, hovering a key highlights it in the chart. Keys that don't +/// fit on one line fold behind an "N more" button. +struct ChartLegend: View { + let entries: [LegendEntry] + var hidden: Binding>? + var highlighted: Binding? + @State private var expanded = false + @State private var width: CGFloat = 0 + + var body: some View { + Group { + if width == 0 { + // One clipped line until the width is known, the height the folded + // legend has, so nothing jumps when it folds. + HStack(spacing: Self.gap) { + ForEach(entries) { item($0).fixedSize() } + } + .frame(maxWidth: .infinity) + .clipped() + } else { + let fitting = Self.fittingCount( + entries.map(Self.width), available: width, + button: Self.buttonWidth(entries.count)) + FlowLayout(spacing: Self.gap, alignment: .center) { + ForEach(entries.prefix(expanded ? entries.count : fitting)) { item($0) } + if fitting < entries.count { + Button { + withOpenUIAnimation(Motion.reveal) { expanded.toggle() } + } label: { + HStack(spacing: 2) { + Text(expanded ? "Show Less" : "\(entries.count - fitting) more") + Image(systemName: expanded ? "chevron.up" : "chevron.down").imageScale(.small) + } + .font(.caption) + } + .buttonStyle(.plain) + } + } + .frame(maxWidth: .infinity) + } + } + .onGeometryChange(for: CGFloat.self) { + $0.size.width + } action: { + width = $0 + } + } + + @ViewBuilder + private func item(_ entry: LegendEntry) -> some View { + let isHidden = hidden?.wrappedValue.contains(entry.id) ?? false + let key = HStack(spacing: 6) { + RoundedRectangle(cornerRadius: 2).fill(entry.color).frame(width: 10, height: 10) + Text(entry.label).font(.caption) + if let percentage = entry.percentage { + Text(ChartFormat.toFixed(percentage, 1) + "%").font(.caption).foregroundStyle(.secondary) + } + } + .opacity(isHidden ? 0.3 : 1) + .contentShape(Rectangle()) + .onHover { inside in highlighted?.wrappedValue = inside ? entry.id : nil } + if let hidden { + Button { + withOpenUIAnimation(Motion.dataMorph) { + hidden.wrappedValue = Self.toggling( + entry.id, in: hidden.wrappedValue, keys: entries.map(\.id)) + } + } label: { + key + } + .buttonStyle(.plain) + .accessibilityValue(isHidden ? "Hidden" : "Shown") + } else { + key.accessibilityElement(children: .combine) + } + } + + /// The gap between keys, react-ui's `space-m`. + static let gap: CGFloat = 12 + + /// react-ui's `useSeriesVisibility`: hides or shows `key`, but never hides + /// the last visible series. + static func toggling(_ key: String, in hidden: Set, keys: [String]) -> Set { + var next = hidden + if next.contains(key) { + next.remove(key) + } else { + guard keys.filter(next.contains).count < keys.count - 1 else { return hidden } + next.insert(key) + } + return next + } + + /// react-ui's `useDefaultLegend`: how many keys fit on one line. All of them + /// if they fit the full width; otherwise as many as fit next to the button, + /// and at least one. + static func fittingCount(_ widths: [CGFloat], available: CGFloat, button: CGFloat) -> Int { + guard available > 0, !widths.isEmpty else { return widths.count } + func count(_ space: CGFloat) -> Int { + var used: CGFloat = 0 + var fitting = 0 + for width in widths { + let needed = fitting > 0 ? width + gap : width + guard used + needed <= space else { break } + used += needed + fitting += 1 + } + return fitting + } + if count(available) == widths.count { return widths.count } + return max(count(available - button), 1) + } + + /// A key's width as react-ui measures it: the text, the 10pt swatch and a gap. + private static func width(_ entry: LegendEntry) -> CGFloat { + var text = entry.label + if let percentage = entry.percentage { text += " (\(ChartFormat.toFixed(percentage, 1))%)" } + return textWidth(text) + 10 + gap + } + + private static func buttonWidth(_ count: Int) -> CGFloat { + textWidth("\(count) more") + 20 + } + + private static func textWidth(_ text: String) -> CGFloat { + #if os(macOS) + let font = NSFont.preferredFont(forTextStyle: .caption1) + #else + let font = UIFont.preferredFont(forTextStyle: .caption1) + #endif + return ceil((text as NSString).size(withAttributes: [.font: font]).width) + } +} + +// MARK: - Tooltip + +/// What a chart's tooltip lists: react-ui's `{ label, items }` payload. +struct ChartTooltipContent: Equatable { + struct Item: Equatable { + let name: String + let value: String + let color: Color + } + + let label: String + let items: [Item] +} + +/// react-ui's ChartTooltip: the label, then a swatch, name and value for each +/// item. One or two items stack each name over its value; more go in rows. Past +/// ten, the first five show with a count of the rest. +struct ChartTooltip: View { + let content: ChartTooltipContent + @Environment(\.openUITheme) private var theme + + var body: some View { + let items = content.items + let shown = items.count > 10 ? Array(items.prefix(5)) : items + VStack(alignment: .leading, spacing: 6) { + Text(content.label) + Divider() + ForEach(Array(shown.enumerated()), id: \.offset) { _, item in + let swatch = RoundedRectangle(cornerRadius: 2).fill(item.color).frame(width: 10, height: 10) + if items.count <= 2 { + HStack(alignment: .top, spacing: 6) { + swatch.padding(.top, 2) + VStack(alignment: .leading, spacing: 4) { + Text(item.name).foregroundStyle(.secondary) + Text(item.value).monospacedDigit() + } + } + } else { + HStack(spacing: 6) { + swatch + Text(item.name).foregroundStyle(.secondary).lineLimit(1) + Spacer(minLength: 8) + Text(item.value).monospacedDigit().lineLimit(1) + } + } + } + if items.count > 10 { + Divider() + Text("\(items.count - 5) more").foregroundStyle(.secondary) + } + } + .font(.caption) + .padding(6) + .frame(minWidth: 128, maxWidth: 240, alignment: .leading) + .fixedSize() + .background(theme.surface, in: RoundedRectangle(cornerRadius: 10)) + .overlay(RoundedRectangle(cornerRadius: 10).strokeBorder(theme.border)) + .shadow(color: .black.opacity(0.08), radius: 4, y: 2) + } +} + +/// Places a tooltip like react-ui's floating one: 20pt right of the anchor, +/// flipped to the left when it would run off the trailing edge, and kept 8pt +/// inside the bounds. `.above` centers it 20pt over the anchor instead, as +/// the stacked bar does. +struct TooltipPlacement: Layout { + enum Placement { case trailing, above } + + let anchor: CGPoint + var placement = Placement.trailing + + func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize { + proposal.replacingUnspecifiedDimensions() + } + + func placeSubviews( + in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout () + ) { + for subview in subviews { + let size = subview.sizeThatFits(.unspecified) + subview.place( + at: Self.origin(for: size, anchor: anchor, placement: placement, in: bounds), + proposal: ProposedViewSize(size)) + } + } + + static func origin( + for size: CGSize, anchor: CGPoint, placement: Placement = .trailing, in bounds: CGRect + ) -> CGPoint { + if placement == .above { + let x = min( + max(bounds.minX + anchor.x - size.width / 2, bounds.minX + 8), bounds.maxX - 8 - size.width) + return CGPoint(x: max(x, bounds.minX), y: bounds.minY + anchor.y - 20 - size.height) + } + var x = bounds.minX + anchor.x + 20 + if x + size.width > bounds.maxX - 8 { x = bounds.minX + anchor.x - 20 - size.width } + x = max(bounds.minX + 8, x) + let y = min( + max(bounds.minY + anchor.y, bounds.minY), max(bounds.maxY - size.height, bounds.minY)) + return CGPoint(x: x, y: y) + } +} + +// MARK: - Picking a category + +/// A category picked by hovering or tapping a chart, and where. +struct ChartSelection: Equatable { + var key: String + var location: CGPoint +} + +/// A clear surface that turns hovering with a pointer (react-ui's mouse move) +/// and tapping (its touch handlers) into a selection: `pick` maps the point to +/// a key. Tapping the same key again clears it, and so does opening another +/// chart's tooltip. A tap doesn't stop a scroll view around the chart from +/// scrolling, which a drag would. +struct PickSurface: View { + @Binding var selection: ChartSelection? + let pick: (CGPoint) -> String? + @State private var hovering = false + @State private var id = UUID() + @Environment(OpenUIContext.self) private var context + + var body: some View { + Rectangle() + .fill(.clear) + .contentShape(Rectangle()) + .onContinuousHover { phase in + switch phase { + case .active(let location): + hovering = true + selection = choose(location) + case .ended: + hovering = false + selection = nil + } + } + .onTapGesture { location in + let picked = choose(location) + // Under a pointer, a click lands on what hovering already picked. + selection = !hovering && picked?.key == selection?.key ? nil : picked + } + .accessibilityHidden(true) + .onChange(of: selection) { _, selection in + if selection != nil { context.chartWithTooltip = id } + } + .onChange(of: context.chartWithTooltip) { _, chart in + if chart != id { selection = nil } + } + } + + private func choose(_ location: CGPoint) -> ChartSelection? { + pick(location).map { ChartSelection(key: $0, location: location) } + } +} + +/// Picks what's under the pointer or a tap on a Swift Charts chart, then +/// draws `crosshair` for it (behind or over the marks) and a tooltip. +struct ChartPicker: ViewModifier { + var crosshairBehind = false + let pick: (CGPoint, ChartProxy, CGRect) -> String? + let tooltip: (String) -> ChartTooltipContent? + @Binding var selection: ChartSelection? + @ViewBuilder let crosshair: (ChartProxy, CGRect, String) -> Crosshair + + func body(content: Content) -> some View { + content + .chartBackground { proxy in + GeometryReader { geometry in + if crosshairBehind, let key = selection?.key, let frame = proxy.plotFrame { + crosshair(proxy, geometry[frame], key) + } + } + } + .chartOverlay { proxy in + GeometryReader { geometry in + let plot = proxy.plotFrame.map { geometry[$0] } ?? .zero + ZStack(alignment: .topLeading) { + if !crosshairBehind, let key = selection?.key { + crosshair(proxy, plot, key) + } + PickSurface(selection: $selection) { location in + plot.contains(location) ? pick(location, proxy, plot) : nil + } + if let selection, let content = tooltip(selection.key) { + TooltipPlacement(anchor: selection.location) { ChartTooltip(content: content) } + .allowsHitTesting(false) + } + } + } + } + } +} + +extension View { + /// Picks the category under the pointer or a tap on a chart with + /// categories along `axis`. + func categoryPicker( + _ selection: Binding, axis: Axis = .horizontal, crosshairBehind: Bool = false, + tooltip: @escaping (String) -> ChartTooltipContent?, + @ViewBuilder crosshair: @escaping (ChartProxy, CGRect, String) -> Crosshair + ) -> some View { + modifier( + ChartPicker( + crosshairBehind: crosshairBehind, + pick: { location, proxy, plot in + axis == .horizontal + ? proxy.value(atX: location.x - plot.minX, as: String.self) + : proxy.value(atY: location.y - plot.minY, as: String.self) + }, + tooltip: tooltip, selection: selection, crosshair: crosshair)) + } +} + +/// react-ui's bar crosshair: a faint rounded band behind the picked category, +/// as wide as its bars' band. +struct BandHighlight: View { + let center: CGFloat + let slot: CGFloat + let plot: CGRect + var axis: Axis = .horizontal + + var body: some View { + let band = RoundedRectangle(cornerRadius: 4).fill(Color.primary.opacity(0.04)) + if axis == .horizontal { + band.frame(width: slot * 0.8, height: plot.height).position( + x: plot.minX + center, y: plot.midY) + } else { + band.frame(width: plot.width, height: slot * 0.8).position( + x: plot.midX, y: plot.minY + center) + } + } +} + +/// react-ui's line and area crosshair: a dashed line down the picked category +/// and a dot on each series there. +struct LineCrosshair: View { + let x: CGFloat + let plot: CGRect + let dots: [(y: CGFloat, color: Color)] + @Environment(\.openUITheme) private var theme + + var body: some View { + ZStack(alignment: .topLeading) { + Path { path in + path.move(to: CGPoint(x: plot.minX + x, y: plot.minY)) + path.addLine(to: CGPoint(x: plot.minX + x, y: plot.maxY)) + } + .stroke(theme.interactiveBorder, style: StrokeStyle(lineWidth: 1, dash: [4, 4])) + ForEach(Array(dots.enumerated()), id: \.offset) { _, dot in + Circle() + .fill(theme.surface) + .overlay(Circle().strokeBorder(theme.interactiveBorder)) + .overlay(Circle().fill(dot.color).padding(2)) + .frame(width: 8, height: 8) + .position(x: plot.minX + x, y: plot.minY + dot.y) + } + } + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift index be5fc1d0db..a332756581 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift @@ -32,6 +32,10 @@ public final class OpenUIContext { /// Bumped whenever the response, `$state` or query results change. public private(set) var revision = 0 + /// The chart whose tooltip is open. A tapped tooltip stays open until it's + /// tapped again, so opening another one closes it. + var chartWithTooltip: UUID? + @ObservationIgnored var onAction: ((ActionEvent) -> Void)? @ObservationIgnored var onStateUpdate: ((OpenUIObject) -> Void)? @ObservationIgnored var onParseResult: ((ParseResult?) -> Void)? diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift index 44026aeada..beff6803cb 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift @@ -342,6 +342,8 @@ struct MarkdownBlocks: View { /// Lays children out in rows, wrapping to the next row when one is full. struct FlowLayout: Layout { var spacing: CGFloat = 8 + /// `.center` centers each row, like react-ui's centered legends. + var alignment = HorizontalAlignment.leading func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize { let rows = arrange(subviews, width: proposal.width ?? .infinity) @@ -355,7 +357,7 @@ struct FlowLayout: Layout { ) { var y = bounds.minY for row in arrange(subviews, width: bounds.width) { - var x = bounds.minX + var x = alignment == .center ? bounds.minX + (bounds.width - row.width) / 2 : bounds.minX for index in row.indices { let size = subviews[index].sizeThatFits(.unspecified) subviews[index].place(at: CGPoint(x: x, y: y), proposal: ProposedViewSize(size)) diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chart-formats.json b/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chart-formats.json new file mode 100644 index 0000000000..b2b2c2c559 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chart-formats.json @@ -0,0 +1,147 @@ +[ + { + "value": 0, + "tick": "0", + "tooltip": "0" + }, + { + "value": 1, + "tick": "1", + "tooltip": "1" + }, + { + "value": -1, + "tick": "-1", + "tooltip": "-1" + }, + { + "value": 7, + "tick": "7", + "tooltip": "7" + }, + { + "value": 0.5, + "tick": "0.50", + "tooltip": "0.5" + }, + { + "value": 0.125, + "tick": "0.13", + "tooltip": "0.125" + }, + { + "value": 1.005, + "tick": "1.00", + "tooltip": "1.005" + }, + { + "value": 1.25, + "tick": "1.25", + "tooltip": "1.25" + }, + { + "value": 12.345, + "tick": "12.35", + "tooltip": "12.345" + }, + { + "value": -0.04, + "tick": "-0.04", + "tooltip": "-0.04" + }, + { + "value": 0.005, + "tick": "0.01", + "tooltip": "0.005" + }, + { + "value": 999, + "tick": "999", + "tooltip": "999" + }, + { + "value": 999.99, + "tick": "999.99", + "tooltip": "999.99" + }, + { + "value": 1000, + "tick": "1.0K", + "tooltip": "1,000" + }, + { + "value": 1250, + "tick": "1.3K", + "tooltip": "1,250" + }, + { + "value": 9999, + "tick": "10.0K", + "tooltip": "9,999" + }, + { + "value": 10000, + "tick": "10K", + "tooltip": "10,000" + }, + { + "value": 15500, + "tick": "16K", + "tooltip": "15,500" + }, + { + "value": -2500, + "tick": "-2.5K", + "tooltip": "-2,500" + }, + { + "value": 99999.5, + "tick": "100K", + "tooltip": "99,999.5" + }, + { + "value": 100000, + "tick": "100K", + "tooltip": "100K" + }, + { + "value": 123456, + "tick": "123K", + "tooltip": "123.4K" + }, + { + "value": 999999, + "tick": "1000K", + "tooltip": "999.9K" + }, + { + "value": 1234567, + "tick": "1.2M", + "tooltip": "1.2M" + }, + { + "value": -7654321, + "tick": "-7.7M", + "tooltip": "-7.6M" + }, + { + "value": 2500000000, + "tick": "2.5B", + "tooltip": "2.5B" + }, + { + "value": 1000000000000, + "tick": "1.0T", + "tooltip": "1T" + }, + { + "value": 15000000000000, + "tick": "15T", + "tooltip": "15T" + }, + { + "value": 1.23456, + "tick": "1.23", + "tooltip": "1.235" + } +] diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 354e16d93b..32ffe30204 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -489,3 +489,104 @@ let globalTestLibrary = SwiftUILibrary( #expect(GalleryMosaic.height(width: 1200, count: 5) == GalleryMosaic.maxHeight) } } + +/// Chart interactions against react-ui: its number formats (fixtures from its +/// formatters), legend folding and toggling, and where pie slices, stacked +/// bar segments and tooltips land. Main actor, because the legend's helpers +/// are members of a view. +@MainActor +@Suite struct ChartInteractionTests { + private struct FormatCase: Decodable { + let value: Double + let tick: String + let tooltip: String + } + + @Test func formatsNumbersLikeReactUI() throws { + let url = Bundle.module.url( + forResource: "chart-formats", withExtension: "json", subdirectory: "Fixtures")! + let cases = try JSONDecoder().decode([FormatCase].self, from: Data(contentsOf: url)) + #expect(cases.count > 20) + for item in cases { + #expect(ChartFormat.tick(item.value) == item.tick, "tick \(item.value)") + #expect( + ChartFormat.tooltip(item.value, locale: Locale(identifier: "en_US")) == item.tooltip, + "tooltip \(item.value)") + } + } + + @Test func keepsOneSeriesVisible() { + let keys = ["a", "b", "c"] + var hidden = ChartLegend.toggling("a", in: [], keys: keys) + hidden = ChartLegend.toggling("b", in: hidden, keys: keys) + #expect(hidden == ["a", "b"]) + #expect(ChartLegend.toggling("c", in: hidden, keys: keys) == ["a", "b"]) + #expect(ChartLegend.toggling("a", in: hidden, keys: keys) == ["b"]) + // Keys from older data don't count against the current series. + #expect(ChartLegend.toggling("a", in: ["gone"], keys: ["a", "b"]) == ["gone", "a"]) + } + + @Test func foldsTheLegendLikeUseDefaultLegend() { + // Each key's width already includes a gap; keys after the first add another. + #expect(ChartLegend.fittingCount([50, 50, 50], available: 174, button: 60) == 3) + #expect(ChartLegend.fittingCount([50, 50, 50], available: 173, button: 60) == 2) + #expect(ChartLegend.fittingCount([50, 50, 50, 50], available: 200, button: 40) == 2) + #expect(ChartLegend.fittingCount([300, 50], available: 200, button: 40) == 1) + #expect(ChartLegend.fittingCount([50, 50], available: 0, button: 40) == 2) + } + + @Test func sortsSlicesLargestFirst() { + let slices = [ + Slice(id: 0, label: "a", value: 1), Slice(id: 1, label: "b", value: 5), + Slice(id: 2, label: "c", value: 5), Slice(id: 3, label: "d", value: 3), + ] + let sorted = sortedSlices(slices, nil) + #expect(sorted.map(\.slice.label) == ["b", "c", "d", "a"]) + #expect(sorted.map(\.color) == ChartPalette.colors(4)) + } + + @Test func findsPieSlicesClockwiseFromTwelve() { + let size = CGSize(width: 200, height: 200) + let values: [Double] = [1, 1, 2] + func slice(_ x: CGFloat, _ y: CGFloat, inner: CGFloat = 0, semi: Bool = false) -> Int? { + PieGeometry.slice( + at: CGPoint(x: x, y: y), in: size, values: values, innerRatio: inner, semicircle: semi) + } + #expect(slice(150, 60) == 0) // upper right + #expect(slice(150, 140) == 1) // lower right + #expect(slice(50, 100) == 2) // left + #expect(slice(100, 100, inner: 0.6) == nil) // the donut's hole + #expect(slice(5, 5) == nil) // outside the circle + // A semicircle is turned a quarter to the left: it starts at 9 o'clock. + #expect(slice(40, 90, semi: true) == 0) + #expect(slice(160, 90, semi: true) == 2) + #expect(slice(100, 160, semi: true) == nil) // the empty lower half + } + + @Test func splitsTheStackedBarByShare() { + let widths = SegmentRow.widths(204, [0.5, 0.25, 0.25]) + #expect(widths == [100, 50, 50]) + #expect(SegmentRow.index(at: 10, width: 204, shares: [0.5, 0.25, 0.25]) == 0) + #expect(SegmentRow.index(at: 120, width: 204, shares: [0.5, 0.25, 0.25]) == 1) + #expect(SegmentRow.index(at: 200, width: 204, shares: [0.5, 0.25, 0.25]) == 2) + } + + @Test func placesTooltipsLikeFloatingUI() { + let bounds = CGRect(x: 0, y: 0, width: 400, height: 200) + let size = CGSize(width: 150, height: 80) + // Right of the pointer, flipped left near the trailing edge, kept inside. + #expect( + TooltipPlacement.origin(for: size, anchor: CGPoint(x: 50, y: 30), in: bounds) + == CGPoint(x: 70, y: 30)) + #expect( + TooltipPlacement.origin(for: size, anchor: CGPoint(x: 300, y: 30), in: bounds) + == CGPoint(x: 130, y: 30)) + #expect( + TooltipPlacement.origin(for: size, anchor: CGPoint(x: 300, y: 190), in: bounds) + == CGPoint(x: 130, y: 120)) + #expect( + TooltipPlacement.origin( + for: size, anchor: CGPoint(x: 10, y: 10), placement: .above, in: bounds) + == CGPoint(x: 8, y: -90)) + } +} From f3452528a73be27e36f0988aae84b9ddcead5d06 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:08:15 +0530 Subject: [PATCH 27/52] feat(swift-lang): add react-ui's general openuiLibrary OpenUILibrary.library renders react-ui's openuiLibrary, for apps that aren't a chat. It shares the chat library's views and adds: - Stack, the root: a flex row or column with react-ui's gap tokens, align, justify and wrap. Cards in a row share the width like react-ui's flex: 1 cards; other views keep their size and shrink in proportion. - Card with Stack's layout props and its card, sunk and clear variants. - Modal: a sheet its $boolean open binding shows. Closing it (the X, Escape, a swipe) writes false back, like react-ui's useStateField. The schemas (OpenUIComponents) come from the same generator as the chat ones and reuse ChatComponents for the 76 components both libraries define the same way. The schema tests now cover both libraries against Zod, including the full JSON Schema and both prompts byte for byte, and the general library's examples join the parser, streaming, evaluation and end-to-end render fixtures. --- packages/swift-lang/.gitattributes | 1 + packages/swift-lang/README.md | 12 +- .../Scripts/generate-chat-components.mjs | 163 +- .../swift-lang/Scripts/generate-fixtures.mjs | 28 +- .../Sources/OpenUILang/OpenUIComponents.swift | 388 + .../Components/StackComponents.swift | 324 + .../Sources/OpenUISwiftUI/OpenUILibrary.swift | 29 + .../OpenUILangTests/ChatComponentsTests.swift | 77 - .../OpenUILangTests/Fixtures/evaluation.json | 1178 ++ .../OpenUILangTests/Fixtures/openui-spec.json | 4752 ++++++++ .../OpenUILangTests/Fixtures/parser.json | 1297 +++ .../OpenUILangTests/Fixtures/prompts.json | 9537 +++++++++++++++++ .../OpenUILangTests/Fixtures/schemas.json | 4253 ++++++++ .../OpenUILangTests/Fixtures/streaming.json | 2 +- .../LibraryComponentsTests.swift | 107 + .../Fixtures/openui-examples.json | 26 + .../OpenUISwiftUITests/RendererTests.swift | 146 + 17 files changed, 22190 insertions(+), 130 deletions(-) create mode 100644 packages/swift-lang/Sources/OpenUILang/OpenUIComponents.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Components/StackComponents.swift create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/OpenUILibrary.swift delete mode 100644 packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/Fixtures/openui-spec.json create mode 100644 packages/swift-lang/Tests/OpenUILangTests/LibraryComponentsTests.swift create mode 100644 packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/openui-examples.json diff --git a/packages/swift-lang/.gitattributes b/packages/swift-lang/.gitattributes index 7695fe78a1..f44e762b9b 100644 --- a/packages/swift-lang/.gitattributes +++ b/packages/swift-lang/.gitattributes @@ -2,3 +2,4 @@ Tests/OpenUILangTests/Fixtures/*.json linguist-generated=true Tests/OpenUISwiftUITests/Fixtures/*.json linguist-generated=true Sources/OpenUILang/ChatComponents.swift linguist-generated=true +Sources/OpenUILang/OpenUIComponents.swift linguist-generated=true diff --git a/packages/swift-lang/README.md b/packages/swift-lang/README.md index 528bc43b3c..2a55c83e46 100644 --- a/packages/swift-lang/README.md +++ b/packages/swift-lang/README.md @@ -126,6 +126,16 @@ The views follow react-ui's layouts and behavior rather than restyling them: car The schemas in `ChatComponents` live in `OpenUILang`, without SwiftUI, so a Swift server can build the chat prompt too. They're generated from `openuiChatLibrary` (see [Testing Locally](#testing-locally)). +### The general library + +`OpenUILibrary.library` is react-ui's general `openuiLibrary`, for apps that aren't a chat: the same views without the chat-only follow-ups and sections, plus `Stack` (the root, a flex row or column), `Modal` (a sheet its `$boolean` binding opens; closing it writes `false` back) and a `Card` that takes Stack's layout props. Its schemas and prompt options are `OpenUIComponents`. + +```swift +OpenUIRenderer(response: text, isStreaming: isStreaming, library: OpenUILibrary.library) + +let prompt = OpenUILibrary.library.prompt(OpenUIComponents.promptOptions) +``` + ## API Reference ### Component Definition @@ -227,7 +237,7 @@ swift test swift format lint --strict -r Sources Tests Package.swift ``` -The conformance fixtures in `Tests/OpenUILangTests/Fixtures` are generated from the TypeScript packages, which are the source of truth. They cover batch and streaming parsing, prop evaluation, prompts, OpenUI Cloud config, edit-mode merging, error hints, OpenUI Cloud's message format, the chart number formats and the chat library schemas. After changing `lang-core`, the chat library, react-ui's `sentinelParser` or its chart formatters, rebuild and regenerate them (the script imports react-ui's TypeScript source directly, so it needs Node 22.18 or newer), and regenerate `ChatComponents.swift` when the chat library changed: +The conformance fixtures in `Tests/OpenUILangTests/Fixtures` are generated from the TypeScript packages, which are the source of truth. They cover batch and streaming parsing, prop evaluation, prompts, OpenUI Cloud config, edit-mode merging, error hints, OpenUI Cloud's message format, the chart number formats, and the schemas, prompts and examples of both libraries. After changing `lang-core`, react-ui's libraries, its `sentinelParser` or its chart formatters, rebuild and regenerate them (the script imports react-ui's TypeScript source directly, so it needs Node 22.18 or newer), and regenerate `ChatComponents.swift` and `OpenUIComponents.swift` when either library changed: ```bash pnpm run build:packages diff --git a/packages/swift-lang/Scripts/generate-chat-components.mjs b/packages/swift-lang/Scripts/generate-chat-components.mjs index 479026e41a..e255b3122f 100644 --- a/packages/swift-lang/Scripts/generate-chat-components.mjs +++ b/packages/swift-lang/Scripts/generate-chat-components.mjs @@ -1,11 +1,12 @@ -// Regenerates Sources/OpenUILang/ChatComponents.swift from openuiChatLibrary in -// @openuidev/react-ui, so the Swift chat library can't drift from the web one. +// Regenerates Sources/OpenUILang/ChatComponents.swift and OpenUIComponents.swift +// from openuiChatLibrary and openuiLibrary in @openuidev/react-ui, so the Swift +// libraries can't drift from the web ones. // // pnpm run build:packages // node packages/swift-lang/Scripts/generate-chat-components.mjs // -// The output is formatted with `swift format`. ChatComponentsTests checks the -// result against the fixtures from generate-fixtures.mjs. +// The output is formatted with `swift format`. LibraryComponentsTests checks +// the result against the fixtures from generate-fixtures.mjs. import { execFileSync } from "node:child_process"; import { writeFileSync } from "node:fs"; @@ -14,7 +15,7 @@ import { fileURLToPath } from "node:url"; const here = dirname(fileURLToPath(import.meta.url)); const packages = join(here, "..", ".."); -const output = join(here, "..", "Sources", "OpenUILang", "ChatComponents.swift"); +const sources = join(here, "..", "Sources", "OpenUILang"); // Code generation is not product usage, so keep lang-core's telemetry off. process.env.OPENUI_TELEMETRY_DISABLED = "1"; @@ -22,11 +23,9 @@ process.env.OPENUI_TELEMETRY_DISABLED = "1"; const core = await import(join(packages, "lang-core", "dist", "index.mjs")); const ui = await import(join(packages, "react-ui", "dist", "genui-lib", "index.mjs")); -const library = ui.openuiChatLibrary; -const defs = library.toJSONSchema().$defs; -const spec = library.toSpec(); -const names = Object.keys(spec.components); -const known = new Set(names); +// The library being generated; set by generate() below. +let library; +let known; // ── Swift literals ──────────────────────────────────────────────────────── @@ -108,69 +107,137 @@ function props(schema, component) { }); } -// ── ChatComponents.swift ────────────────────────────────────────────────── +// ── Output ──────────────────────────────────────────────────────────────── const lowerFirst = (name) => name[0].toLowerCase() + name.slice(1); - -const schemas = names.map( - (name) => ` public static let ${lowerFirst(name)} = ComponentSchema( +const swiftLines = (items) => items.map((item) => ` ${swiftString(item)},`).join("\n"); + +/// Writes `enumName` with a schema per component, the groups and the prompt +/// options. Components defined exactly as in `shared` (same JSON Schema and +/// bindings) reuse its schemas instead of repeating them. +function generate({ lib, promptOptions, enumName, docs, shared }) { + library = lib; + const defs = lib.toJSONSchema().$defs; + const spec = lib.toSpec(); + const names = Object.keys(spec.components); + known = new Set(names); + const reused = (name) => { + if (!shared?.lib.components[name]) return false; + const other = shared.lib.toJSONSchema().$defs[name]; + const reactive = (l) => + Object.entries(l.components[name].props.shape) + .filter(([, s]) => core.isReactiveSchema(s)) + .map(([key]) => key) + .join(); + return ( + JSON.stringify(other) === JSON.stringify(defs[name]) && reactive(shared.lib) === reactive(lib) + ); + }; + + const schemas = names + .filter((name) => !reused(name)) + .map( + (name) => ` public static let ${lowerFirst(name)} = ComponentSchema( ${swiftString(name)}, description: ${swiftString(defs[name].description ?? "")}, props: [${props(defs[name], name).join(", ")}]) `, -); - -const groups = spec.componentGroups.map((group) => { - const notes = group.notes?.length ? `, notes: [${group.notes.map(swiftString).join(", ")}]` : ""; - return ` ComponentGroup(name: ${swiftString(group.name)}, components: [${group.components.map(swiftString).join(", ")}]${notes}),`; -}); - -const { examples, additionalRules } = ui.openuiChatPromptOptions; - -writeFileSync( - output, - `// Generated by Scripts/generate-chat-components.mjs from openuiChatLibrary in -// @openuidev/react-ui. Don't edit by hand. -// swift-format-ignore-file: LineLength - -/// Schemas for the OpenUI chat library. Names, prop order, types and -/// descriptions match \`openuiChatLibrary\` in @openuidev/react-ui, so a backend -/// that prompts with either library produces responses both can render. -/// -/// The schemas live in \`OpenUILang\`, without SwiftUI, so a server can build -/// the chat prompt or Cloud config for them too. -public enum ChatComponents { - /// The structured \`rules\` object shared by form fields. + ); + const groups = spec.componentGroups.map((group) => { + const notes = group.notes?.length + ? `, notes: [${group.notes.map(swiftString).join(", ")}]` + : ""; + return ` ComponentGroup(name: ${swiftString(group.name)}, components: [${group.components.map(swiftString).join(", ")}]${notes}),`; + }); + const all = names.map( + (name) => ` ${reused(name) ? `${shared.enumName}.` : ""}${lowerFirst(name)},`, + ); + const formRules = shared + ? ` /// The form \`rules\` object, for schemas that aren't shared. + static let formRules = ${shared.enumName}.formRules + +` + : ` /// The structured \`rules\` object shared by form fields. public static let formRules: PropType = .object( ["required", "email", "url", "numeric"].map { Prop($0, .boolean, .optional) } + ["min", "max", "minLength", "maxLength"].map { Prop($0, .number, .optional) } + [Prop("pattern", .string, .optional)]) -${schemas.join("\n")} - /// Prompt groups and notes, as in openuiChatLibrary. +`; + const output = join(sources, `${enumName}.swift`); + writeFileSync( + output, + `// Generated by Scripts/generate-chat-components.mjs from ${docs.source} in +// @openuidev/react-ui. Don't edit by hand. +// swift-format-ignore-file: LineLength + +${docs.comment} +public enum ${enumName} { +${formRules}${schemas.join("\n")} + /// Prompt groups and notes, as in ${docs.source}. public static let groups: [ComponentGroup] = [ ${groups.join("\n")} ] /// Every schema, in library order. public static let all: [ComponentSchema] = [ -${names.map((name) => ` ${lowerFirst(name)},`).join("\n")} +${all.join("\n")} ] - /// Example responses for the prompt (\`openuiChatExamples\`). + /// Example responses for the prompt (\`${docs.examples}\`). public static let examples: [String] = [ -${examples.map((example) => ` ${swiftString(example)},`).join("\n")} +${swiftLines(promptOptions.examples)} ] - /// Extra prompt rules for this library (\`openuiChatAdditionalRules\`). + /// Extra prompt rules for this library (\`${docs.rules}\`). public static let additionalRules: [String] = [ -${additionalRules.map((rule) => ` ${swiftString(rule)},`).join("\n")} +${swiftLines(promptOptions.additionalRules)} ] - /// The prompt options react-ui pairs with this library (\`openuiChatPromptOptions\`). + /// The prompt options react-ui pairs with this library (\`${docs.options}\`). public static let promptOptions = PromptOptions( additionalRules: additionalRules, examples: examples) } `, -); -execFileSync("swift", ["format", "-i", output]); -console.log(`wrote ${names.length} chat component schemas to ${output}`); + ); + execFileSync("swift", ["format", "-i", output]); + console.log( + `wrote ${names.length} ${docs.source} schemas to ${output}` + + (shared ? ` (${names.filter(reused).length} shared with ${shared.enumName})` : ""), + ); +} + +const chat = { + lib: ui.openuiChatLibrary, + promptOptions: ui.openuiChatPromptOptions, + enumName: "ChatComponents", + docs: { + source: "openuiChatLibrary", + examples: "openuiChatExamples", + rules: "openuiChatAdditionalRules", + options: "openuiChatPromptOptions", + comment: `/// Schemas for the OpenUI chat library. Names, prop order, types and +/// descriptions match \`openuiChatLibrary\` in @openuidev/react-ui, so a backend +/// that prompts with either library produces responses both can render. +/// +/// The schemas live in \`OpenUILang\`, without SwiftUI, so a server can build +/// the chat prompt or Cloud config for them too.`, + }, +}; +generate(chat); +generate({ + lib: ui.openuiLibrary, + promptOptions: ui.openuiPromptOptions, + enumName: "OpenUIComponents", + shared: chat, + docs: { + source: "openuiLibrary", + examples: "openuiExamples", + rules: "openuiAdditionalRules", + options: "openuiPromptOptions", + comment: `/// Schemas for react-ui's general OpenUI library, \`openuiLibrary\`: the chat +/// library's components without the chat-only follow-ups and sections, plus +/// \`Stack\` (the root) and \`Modal\`, with \`Card\` taking Stack's layout props. +/// Components both libraries define the same way are \`ChatComponents\`' +/// schemas.`, + }, +}); diff --git a/packages/swift-lang/Scripts/generate-fixtures.mjs b/packages/swift-lang/Scripts/generate-fixtures.mjs index 64ed0d8bbf..b1e251d43d 100644 --- a/packages/swift-lang/Scripts/generate-fixtures.mjs +++ b/packages/swift-lang/Scripts/generate-fixtures.mjs @@ -25,6 +25,8 @@ const ui = await import(join(packages, "react-ui", "dist", "genui-lib", "index.m // ── Schemas ─────────────────────────────────────────────────────────────── const chatSchema = ui.openuiChatLibrary.toJSONSchema(); +// react-ui's general library: the chat components plus Stack (its root) and Modal. +const openuiSchema = ui.openuiLibrary.toJSONSchema(); // Small hand-written schema that exercises validation paths the chat library // doesn't: defaults, const, integer, nested required keys, enum defaults. @@ -135,10 +137,11 @@ const hoistedSchema = { const schemas = { chat: { schema: chatSchema, root: "Card", reactive: reactiveProps(ui.openuiChatLibrary) }, + openui: { schema: openuiSchema, root: "Stack", reactive: reactiveProps(ui.openuiLibrary) }, test: { schema: testSchema, root: "Card", reactive: testReactive }, hoisted: { schema: hoistedSchema, root: "Tree", reactive: {} }, }; -const libraries = { chat: ui.openuiChatLibrary, test: testLibrary }; +const libraries = { chat: ui.openuiChatLibrary, openui: ui.openuiLibrary, test: testLibrary }; // ── Corpus ──────────────────────────────────────────────────────────────── @@ -148,6 +151,12 @@ const chatExamples = ui.openuiChatPromptOptions.examples.map((text, i) => ({ input: text, })); +const openuiExamples = ui.openuiPromptOptions.examples.map((text, i) => ({ + name: `openui-example-${i + 1}`, + schema: "openui", + input: text, +})); + const t = (name, input) => ({ name, schema: "test", input }); const edgeCases = [ @@ -290,12 +299,12 @@ function streamCheckpoints(schemaName, input) { }); } -const parserCases = [...chatExamples, ...edgeCases].map((c) => ({ +const parserCases = [...chatExamples, ...openuiExamples, ...edgeCases].map((c) => ({ ...c, expected: parseWith(c.schema, c.input), })); -const streamingCases = [...chatExamples, ...edgeCases] +const streamingCases = [...chatExamples, ...openuiExamples, ...edgeCases] .filter((c) => c.input.length > 0) .map((c) => ({ ...c, checkpoints: streamCheckpoints(c.schema, c.input) })); @@ -337,6 +346,7 @@ const e = (name, input, extra = {}) => ({ name, schema: "test", input, ...extra const evalCases = [ ...chatExamples, + ...openuiExamples, e("operators", edgeCases.find((c) => c.name === "operators").input), e("member-index", edgeCases.find((c) => c.name === "member-index").input), e("actions", edgeCases.find((c) => c.name === "actions").input), @@ -379,6 +389,7 @@ const evalFixtures = evalCases.map((c) => ({ ...c, expected: evaluateCase(c) })) // ── Prompts ─────────────────────────────────────────────────────────────── const chatSpec = ui.openuiChatLibrary.toSpec(); +const openuiSpec = ui.openuiLibrary.toSpec(); delete chatSpec.schema; // already in schemas.json const tools = [ @@ -443,6 +454,8 @@ const sliceSpec = { const promptCases = [ { name: "chat-default", spec: chatSpec }, { name: "chat-options", spec: { ...chatSpec, ...ui.openuiChatPromptOptions } }, + { name: "openui-default", spec: openuiSpec }, + { name: "openui-options", spec: { ...openuiSpec, ...ui.openuiPromptOptions } }, { name: "slice-bindings", spec: { ...sliceSpec, bindings: true } }, { name: "slice-tools", @@ -780,6 +793,15 @@ writeFileSync( ) + "\n", ); write("chat-spec.json", chatComponentSpecs); +write("openui-spec.json", openuiSpec); +writeFileSync( + join(here, "..", "Tests", "OpenUISwiftUITests", "Fixtures", "openui-examples.json"), + JSON.stringify( + openuiExamples.map(({ name, input }) => ({ name, input })), + null, + 1, + ) + "\n", +); writeFileSync( join(here, "..", "Tests", "OpenUISwiftUITests", "Fixtures", "chart-formats.json"), JSON.stringify(chartFormatCases, null, 1) + "\n", diff --git a/packages/swift-lang/Sources/OpenUILang/OpenUIComponents.swift b/packages/swift-lang/Sources/OpenUILang/OpenUIComponents.swift new file mode 100644 index 0000000000..ffbd55441c --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/OpenUIComponents.swift @@ -0,0 +1,388 @@ +// Generated by Scripts/generate-chat-components.mjs from openuiLibrary in +// @openuidev/react-ui. Don't edit by hand. +// swift-format-ignore-file: LineLength + +/// Schemas for react-ui's general OpenUI library, `openuiLibrary`: the chat +/// library's components without the chat-only follow-ups and sections, plus +/// `Stack` (the root) and `Modal`, with `Card` taking Stack's layout props. +/// Components both libraries define the same way are `ChatComponents`' +/// schemas. +public enum OpenUIComponents { + /// The form `rules` object, for schemas that aren't shared. + static let formRules = ChatComponents.formRules + + public static let card = ComponentSchema( + "Card", + description: + "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts.", + props: [ + Prop( + "children", + .array( + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), + .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), + .component("LineChart"), .component("Table"), .component("TagBlock"), + .component("Form"), .component("Buttons"), .component("IconButton"), + .component("Steps"), .component("InlineHeader"), .component("EntityList"), + .component("EditableTable"), .component("SnippetCardBlock"), + .component("OverviewCardBlock"), .component("ContextCardBlock"), + .component("CompositeCardBlock"), .component("VisualCardBlock"), .component("Tabs"), + .component("Carousel"), .component("Stack"), + ]))), Prop("variant", .enumeration(["card", "sunk", "clear"]), .optional), + Prop("direction", .enumeration(["row", "column"]), .optional), + Prop("gap", .enumeration(["none", "xs", "s", "m", "l", "xl", "2xl"]), .optional), + Prop("align", .enumeration(["start", "center", "end", "stretch", "baseline"]), .optional), + Prop( + "justify", .enumeration(["start", "center", "end", "between", "around", "evenly"]), + .optional), Prop("wrap", .boolean, .optional), + ]) + + public static let stack = ComponentSchema( + "Stack", + description: + "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\".", + props: [ + Prop("children", .array(.any)), + Prop("direction", .enumeration(["row", "column"]), .optional), + Prop("gap", .enumeration(["none", "xs", "s", "m", "l", "xl", "2xl"]), .optional), + Prop("align", .enumeration(["start", "center", "end", "stretch", "baseline"]), .optional), + Prop( + "justify", .enumeration(["start", "center", "end", "between", "around", "evenly"]), + .optional), Prop("wrap", .boolean, .optional), + ]) + + public static let tabItem = ComponentSchema( + "TabItem", + description: "value is unique id, trigger is tab label, content is array of components", + props: [ + Prop("value", .string), Prop("trigger", .string), + Prop( + "content", + .array( + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), + .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), + .component("LineChart"), .component("Table"), .component("TagBlock"), + .component("Form"), .component("Buttons"), .component("IconButton"), + .component("Steps"), .component("InlineHeader"), .component("EntityList"), + .component("EditableTable"), .component("SnippetCardBlock"), + .component("OverviewCardBlock"), .component("ContextCardBlock"), + .component("CompositeCardBlock"), .component("VisualCardBlock"), + ]))), + ]) + + public static let accordionItem = ComponentSchema( + "AccordionItem", description: "value is unique id, trigger is section title", + props: [ + Prop("value", .string), Prop("trigger", .string), + Prop( + "content", + .array( + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), + .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), + .component("LineChart"), .component("Table"), .component("TagBlock"), + .component("Form"), .component("Buttons"), .component("IconButton"), + .component("Steps"), .component("InlineHeader"), .component("EntityList"), + .component("EditableTable"), .component("SnippetCardBlock"), + .component("OverviewCardBlock"), .component("ContextCardBlock"), + .component("CompositeCardBlock"), .component("VisualCardBlock"), + ]))), + ]) + + public static let carousel = ComponentSchema( + "Carousel", description: "Horizontal scrollable carousel", + props: [ + Prop( + "children", + .array( + .array( + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), + .component("SingleStackedBarChart"), .component("ScatterChart"), + .component("AreaChart"), .component("BarChart"), .component("LineChart"), + .component("Table"), .component("TagBlock"), .component("Form"), + .component("Buttons"), .component("IconButton"), .component("Steps"), + .component("InlineHeader"), .component("EntityList"), .component("EditableTable"), + .component("SnippetCardBlock"), .component("OverviewCardBlock"), + .component("ContextCardBlock"), .component("CompositeCardBlock"), + .component("VisualCardBlock"), + ])))), Prop("variant", .enumeration(["card", "sunk"]), .optional), + ]) + + public static let modal = ComponentSchema( + "Modal", + description: + "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children.", + props: [ + Prop("title", .string), Prop("open", .boolean, .optional, binding: true), + Prop( + "children", + .array( + .union([ + .component("TextContent"), .component("MarkDownRenderer"), .component("CardHeader"), + .component("Callout"), .component("TextCallout"), .component("CodeBlock"), + .component("Image"), .component("ImageBlock"), .component("ImageGallery"), + .component("Separator"), .component("HorizontalBarChart"), .component("RadarChart"), + .component("PieChart"), .component("RadialChart"), .component("SingleStackedBarChart"), + .component("ScatterChart"), .component("AreaChart"), .component("BarChart"), + .component("LineChart"), .component("Table"), .component("TagBlock"), + .component("Form"), .component("Buttons"), .component("IconButton"), + .component("Steps"), .component("InlineHeader"), .component("EntityList"), + .component("EditableTable"), .component("SnippetCardBlock"), + .component("OverviewCardBlock"), .component("ContextCardBlock"), + .component("CompositeCardBlock"), .component("VisualCardBlock"), + ]))), Prop("size", .enumeration(["sm", "md", "lg"]), .optional), + ]) + + /// Prompt groups and notes, as in openuiLibrary. + public static let groups: [ComponentGroup] = [ + ComponentGroup( + name: "Layout", + components: [ + "Stack", "Tabs", "TabItem", "Accordion", "AccordionItem", "Steps", "StepsItem", "Carousel", + "Separator", "Modal", + ], + notes: [ + "- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.", + "- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.", + "- Use nested Stacks when you need explicit rows/sections.", + "- Show/hide sections: $editId != \"\" ? Card([editForm]) : null", + "- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.", + "- Use Tabs for alternative views (chart types, data sections) — no $variable needed", + "- Shared filter across Tabs: same $days binding in Query args works across all TabItems", + ]), + ComponentGroup( + name: "Content", + components: [ + "Card", "CardHeader", "TextContent", "MarkDownRenderer", "Callout", "TextCallout", "Image", + "ImageBlock", "ImageGallery", "CodeBlock", "InlineHeader", + ], + notes: [ + "- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).", + "- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.", + "- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null", + "- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])", + ]), + ComponentGroup( + name: "Tables", components: ["Table", "Col", "EditableTable"], + notes: [ + "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", + "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.", + "- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName", + "- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))", + "- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))", + "- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data", + "- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input", + "- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts", + "- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")", + ]), + ComponentGroup( + name: "Charts (2D)", + components: [ + "BarChart", "LineChart", "AreaChart", "RadarChart", "HorizontalBarChart", "Series", + ], + notes: [ + "- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])", + "- Use Cards to wrap charts with CardHeader for titled sections", + "- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data", + "- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])", + ]), + ComponentGroup( + name: "Charts (1D)", + components: ["PieChart", "RadialChart", "SingleStackedBarChart", "Slice"], + notes: [ + "- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:", + "- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`", + "- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`", + ]), + ComponentGroup( + name: "Charts (Scatter)", components: ["ScatterChart", "ScatterSeries", "Point"]), + ComponentGroup( + name: "Forms", + components: [ + "Form", "FormControl", "Label", "Input", "TextArea", "Select", "SelectItem", "DatePicker", + "Slider", "CheckBoxGroup", "CheckBoxItem", "RadioGroup", "RadioItem", "SwitchGroup", + "SwitchItem", "Chips", "ChipItem", "OptionCards", "OptionCard", + ], + notes: [ + "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", + "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", + "- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.", + "- NEVER nest Form inside Form — each Form should be a standalone container.", + "- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.", + "- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}", + "- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric", + "- The renderer shows error messages automatically — do NOT generate error text in the UI", + "- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField", + "- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal.", + ]), + ComponentGroup( + name: "Buttons", components: ["Button", "Buttons", "IconButton"], + notes: [ + "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.", + "- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))", + ]), + ComponentGroup( + name: "Data Display", + components: ["TagBlock", "Tag", "Icon", "EntityList", "ListBlock", "ListItem"], + notes: [ + "- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")", + "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.", + "- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional.", + ]), + ComponentGroup( + name: "Cards", + components: [ + "SnippetCardBlock", "SnippetCardItem", "OverviewCardBlock", "OverviewCardItem", + "ContextCardBlock", "ContextCardItem", "CompositeCardBlock", "CompositeCardItem", + "VisualCardBlock", "VisualCardItem", "Text", "BoldText", "IconText", "ImageText", + "ImageTextLarge", "MetricIndicatorInline", "MetricIndicatorWithStrikethrough", + ], + notes: [ + "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", + "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", + "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", + "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", + "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", + "- VisualCardItem: image-first card with a BoldText body and optional Tag.", + "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.", + ]), + ] + + /// Every schema, in library order. + public static let all: [ComponentSchema] = [ + card, + ChatComponents.cardHeader, + ChatComponents.textContent, + ChatComponents.markDownRenderer, + ChatComponents.callout, + ChatComponents.textCallout, + ChatComponents.image, + ChatComponents.imageBlock, + ChatComponents.imageGallery, + ChatComponents.codeBlock, + ChatComponents.inlineHeader, + ChatComponents.table, + ChatComponents.col, + ChatComponents.editableTable, + ChatComponents.barChart, + ChatComponents.lineChart, + ChatComponents.areaChart, + ChatComponents.radarChart, + ChatComponents.horizontalBarChart, + ChatComponents.series, + ChatComponents.pieChart, + ChatComponents.radialChart, + ChatComponents.singleStackedBarChart, + ChatComponents.slice, + ChatComponents.scatterChart, + ChatComponents.scatterSeries, + ChatComponents.point, + ChatComponents.form, + ChatComponents.formControl, + ChatComponents.label, + ChatComponents.input, + ChatComponents.textArea, + ChatComponents.select, + ChatComponents.selectItem, + ChatComponents.datePicker, + ChatComponents.slider, + ChatComponents.checkBoxGroup, + ChatComponents.checkBoxItem, + ChatComponents.radioGroup, + ChatComponents.radioItem, + ChatComponents.switchGroup, + ChatComponents.switchItem, + ChatComponents.chipItem, + ChatComponents.chips, + ChatComponents.optionCard, + ChatComponents.optionCards, + ChatComponents.button, + ChatComponents.buttons, + ChatComponents.iconButton, + stack, + ChatComponents.tabs, + tabItem, + ChatComponents.accordion, + accordionItem, + ChatComponents.steps, + ChatComponents.stepsItem, + carousel, + ChatComponents.separator, + ChatComponents.tagBlock, + ChatComponents.tag, + ChatComponents.icon, + ChatComponents.entityList, + ChatComponents.listBlock, + ChatComponents.listItem, + ChatComponents.text, + ChatComponents.boldText, + ChatComponents.iconText, + ChatComponents.imageText, + ChatComponents.imageTextLarge, + ChatComponents.metricIndicatorInline, + ChatComponents.metricIndicatorWithStrikethrough, + ChatComponents.snippetCardItem, + ChatComponents.snippetCardBlock, + ChatComponents.overviewCardItem, + ChatComponents.overviewCardBlock, + ChatComponents.contextCardItem, + ChatComponents.contextCardBlock, + ChatComponents.compositeCardItem, + ChatComponents.compositeCardBlock, + ChatComponents.visualCardItem, + ChatComponents.visualCardBlock, + modal, + ] + + /// Example responses for the prompt (`openuiExamples`). + public static let examples: [String] = [ + "Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]", + "Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])", + "Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])", + "Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]", + "Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")", + "Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])", + ] + + /// Extra prompt rules for this library (`openuiAdditionalRules`). + public static let additionalRules: [String] = [ + "When asked about data, generate realistic/plausible data", + "For grid-like layouts, use Stack with direction \"row\" and wrap=true. Avoid justify=\"between\" unless you specifically want large gutters.", + "For forms, define one FormControl reference per field so controls can stream progressively.", + "For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).", + "Never nest Form inside Form.", + "Use @Reset($var1, $var2) after form submit to restore defaults — not @Set($var, \"\")", + "Multi-query refresh: Action([@Run(mutation), @Run(query1), @Run(query2), @Reset(...)])", + "$variables are reactive: changing via Select or @Set re-evaluates all Queries and expressions referencing them", + "Use existing components (Tabs, Accordion, Modal) before inventing ternary show/hide patterns", + "Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items; every item in a block must have the same structure.", + "Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicatorInline / MetricIndicatorWithStrikethrough are inline building blocks used INSIDE card items — do not place them directly in a Stack or Card.", + "EntityList size='small' (no header/footer) is only for use inside a CompositeCardItem body; use size='default' everywhere else.", + "Image URLs must be real (from a tool result or the user) — never invent or template an image URL.", + "Always pass a category to Icon — it enables a topical fallback when the exact icon name is unavailable.", + "EditableTable requires the consuming app to persist edits — use it only when the user or app explicitly asks for an editable table; default to Table for read-only data.", + ] + + /// The prompt options react-ui pairs with this library (`openuiPromptOptions`). + public static let promptOptions = PromptOptions( + additionalRules: additionalRules, examples: examples) +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/StackComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/StackComponents.swift new file mode 100644 index 0000000000..93b4b827c0 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/StackComponents.swift @@ -0,0 +1,324 @@ +import OpenUILang +import SwiftUI + +// MARK: - Flex layout + +/// As much of a CSS flex container as react-ui's Stack and Card use: a row or +/// a column with a gap, cross-axis `align`, main-axis `justify` and `wrap`. +/// +/// In a row, views that can grow (a Card, or anything with an infinite max +/// width) act like react-ui's cards, `flex: 1` with `min-width: 0`: they start +/// from nothing and share the free space equally, so they never wrap; other +/// views keep their own width and shrink in proportion when the row is too +/// narrow. Columns place each view at the full width. +struct FlexLayout: Layout { + enum Direction { + case row, column + } + + var direction = Direction.column + var gap: CGFloat = 12 + /// `start`, `center`, `end`, `stretch` or `baseline`; nil is CSS's default, + /// `stretch`. + var align: String? + /// `start`, `center`, `end`, `between`, `around` or `evenly`. + var justify: String? + var wrap = false + + /// A view's starting size along the row and whether it grows. + struct Item: Equatable { + var basis: CGFloat + var flexible: Bool + } + + /// react-ui's spacing tokens for Stack's `gap`, "m" by default. + static func gap(_ name: String?) -> CGFloat { + switch name { + case "none": 0 + case "xs": 6 + case "s": 8 + case "l": 18 + case "xl": 24 + case "2xl": 36 + default: 12 + } + } + + func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize { + let frames = arrange(proposal: proposal, subviews: subviews) + let width = proposal.width ?? frames.map(\.maxX).max() ?? 0 + return CGSize(width: width, height: frames.map(\.maxY).max() ?? 0) + } + + func placeSubviews( + in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout () + ) { + let frames = arrange( + proposal: ProposedViewSize(width: bounds.width, height: nil), subviews: subviews) + for (subview, frame) in zip(subviews, frames) { + subview.place( + at: CGPoint(x: bounds.minX + frame.minX, y: bounds.minY + frame.minY), + proposal: ProposedViewSize(frame.size)) + } + } + + /// Each subview's frame, relative to the container's top-leading corner. + /// Views with no size, like a closed Modal, get no gap around them: in + /// react-ui they render nothing. + private func arrange(proposal: ProposedViewSize, subviews: Subviews) -> [CGRect] { + let shown = subviews.indices.filter { subviews[$0].sizeThatFits(.unspecified) != .zero } + var frames = [CGRect](repeating: .zero, count: subviews.count) + let placed = layOut(proposal: proposal, subviews: shown.map { subviews[$0] }) + for (index, frame) in zip(shown, placed) { frames[index] = frame } + return frames + } + + private func layOut(proposal: ProposedViewSize, subviews: [LayoutSubview]) -> [CGRect] { + if direction == .column { return column(width: proposal.width, subviews: subviews) } + let items = subviews.map { subview in + let ideal = subview.sizeThatFits(.unspecified).width + let flexible = subview.sizeThatFits(ProposedViewSize(width: .infinity, height: nil)).width + .isInfinite + return Item(basis: flexible ? 0 : ideal, flexible: flexible) + } + let width = + proposal.width + ?? subviews.map { $0.sizeThatFits(.unspecified).width }.reduce(0, +) + + gap * CGFloat(max(subviews.count - 1, 0)) + // react-ui's Stack doesn't spread wrapped lines apart. + let justify = wrap && self.justify == "between" ? "start" : self.justify + var frames = [CGRect](repeating: .zero, count: subviews.count) + var y: CGFloat = 0 + for line in Self.lines(items, width: width, gap: gap, wrap: wrap) { + let (widths, offsets) = Self.distribute( + Array(items[line]), width: width, gap: gap, justify: justify) + let heights = zip(line, widths).map { index, width in + subviews[index].sizeThatFits(ProposedViewSize(width: width, height: nil)).height + } + let height = heights.max() ?? 0 + let baselines = zip(line, zip(widths, heights)).map { index, size in + subviews[index].dimensions(in: ProposedViewSize(width: size.0, height: size.1))[ + .firstTextBaseline] + } + let baseline = baselines.max() ?? 0 + for (position, index) in line.enumerated() { + let itemHeight = heights[position] + let stretched = align == nil || align == "stretch" + let offset: CGFloat = + switch align { + case "center": (height - itemHeight) / 2 + case "end": height - itemHeight + case "baseline": baseline - baselines[position] + default: 0 + } + frames[index] = CGRect( + x: offsets[position], y: y + offset, width: widths[position], + height: stretched ? height : itemHeight) + } + y += height + gap + } + return frames + } + + private func column(width proposed: CGFloat?, subviews: [LayoutSubview]) -> [CGRect] { + let width = proposed ?? subviews.map { $0.sizeThatFits(.unspecified).width }.max() ?? 0 + var y: CGFloat = 0 + return subviews.map { subview in + let size = subview.sizeThatFits(ProposedViewSize(width: width, height: nil)) + let itemWidth = align == nil || align == "stretch" ? width : min(size.width, width) + let x: CGFloat = + switch align { + case "center": (width - itemWidth) / 2 + case "end": width - itemWidth + default: 0 + } + defer { y += size.height + gap } + return CGRect(x: x, y: y, width: itemWidth, height: size.height) + } + } + + /// Splits items into lines. Without `wrap` it's one line; with it, items + /// move to a new line when their basis doesn't fit. Growing items start + /// from nothing, so they never move on their own. + static func lines(_ items: [Item], width: CGFloat, gap: CGFloat, wrap: Bool) -> [Range] { + guard wrap, !items.isEmpty else { return [items.indices] } + var lines: [Range] = [] + var start = 0 + var used: CGFloat = 0 + for (index, item) in items.enumerated() { + let needed = index == start ? item.basis : used + gap + item.basis + if index > start, needed > width { + lines.append(start.. (widths: [CGFloat], offsets: [CGFloat]) { + let count = CGFloat(items.count) + let fixed = items.filter { !$0.flexible }.map(\.basis).reduce(0, +) + let free = width - gap * max(count - 1, 0) - fixed + let growing = CGFloat(items.filter(\.flexible).count) + var widths = items.map(\.basis) + if free < 0, fixed > 0 { + widths = items.map { $0.flexible ? 0 : max($0.basis + free * $0.basis / fixed, 0) } + } else if growing > 0 { + widths = items.map { $0.flexible ? free / growing : $0.basis } + } + let space = growing > 0 ? 0 : max(free, 0) + let (lead, between): (CGFloat, CGFloat) = + switch justify { + case "center": (space / 2, 0) + case "end": (space, 0) + case "between": (0, count > 1 ? space / (count - 1) : 0) + case "around": (space / count / 2, space / count) + case "evenly": (space / (count + 1), space / (count + 1)) + default: (0, 0) + } + var x = lead + let offsets = widths.map { width in + defer { x += width + gap + between } + return x + } + return (widths, offsets) + } +} + +extension FlexLayout { + /// The layout a Stack or Card asks for with its flex props. + init(_ props: ComponentProps, defaultAlign: String? = nil) { + self.init( + direction: props.string("direction") == "row" ? .row : .column, + gap: Self.gap(props.string("gap")), align: props.string("align") ?? defaultAlign, + justify: props.string("justify"), wrap: props.bool("wrap") ?? false) + } +} + +/// A list of nodes laid out by `layout`, with OpenUINodes' streaming insertions. +private struct FlexNodes: View { + let layout: FlexLayout + let values: [OpenUIValue] + + var body: some View { + let items = NodeItem.list(values) + layout { + ForEach(items) { item in + OpenUINode(item.value).transition(.openUIInsertion) + } + } + .openUIAnimation(Motion.insertion, value: items.map(\.id)) + } +} + +// MARK: - Stack and Card + +/// openuiLibrary's Stack: a flex container, a column by default. +struct StackView: View { + let props: ComponentProps + + var body: some View { + FlexNodes(layout: FlexLayout(props), values: props.array("children")) + .frame(maxWidth: .infinity, alignment: .leading) + } +} + +/// openuiLibrary's Card: react-ui's card surface ("card", "sunk", or "clear" +/// with only side padding) around a Stack-like flex layout that stretches its +/// children by default. Cards always take the full width, and in a row they +/// share it. +struct FlexCardView: View { + let props: ComponentProps + @Environment(\.openUITheme) private var theme + + var body: some View { + let variant = props.string("variant") ?? "card" + FlexNodes(layout: FlexLayout(props, defaultAlign: "stretch"), values: props.array("children")) + .padding(.horizontal, variant == "clear" ? theme.cardPadding : 0) + .frame(maxWidth: .infinity, alignment: .leading) + .surface(variant) + } +} + +// MARK: - Modal + +/// openuiLibrary's Modal: a sheet that its `open` binding shows (set the bound +/// `$state` to true). Closing it with its button, Escape or a swipe writes +/// false back, as react-ui's X, Escape and backdrop do. +struct ModalView: View { + let props: ComponentProps + @Environment(OpenUIContext.self) private var context + @Environment(\.openUITheme) private var theme + + var body: some View { + let field = context.stateField(name: "open", binding: props["open"], form: nil) + let isOpen = field.value == true || field.value == "true" + Color.clear + .frame(width: 0, height: 0) + .accessibilityHidden(true) + .sheet( + isPresented: Binding( + get: { isOpen }, + set: { open in if !open { field.setValue(false) } }) + ) { + ModalSheet(props: props) + .environment(context) + .environment(\.openUITheme, theme) + } + } +} + +private struct ModalSheet: View { + let props: ComponentProps + @Environment(\.dismiss) private var dismiss + + var body: some View { + VStack(spacing: 0) { + HStack { + Text(props.text("title")).font(.headline) + Spacer() + Button { + dismiss() + } label: { + Image(systemName: "xmark") + .font(.body.weight(.medium)) + .foregroundStyle(.secondary) + .frame(width: 28, height: 28) + .contentShape(Rectangle()) + } + .buttonStyle(.plain) + .keyboardShortcut(.cancelAction) + .accessibilityLabel("Close") + } + .padding(12) + Divider() + ScrollView { + OpenUINodes(props.array("children")) + .padding(12) + .frame(maxWidth: .infinity, alignment: .leading) + } + } + #if os(macOS) + .frame(width: Self.width(props.string("size"))) + .frame(minHeight: 200, idealHeight: 420) + #endif + } + + /// react-ui's sm, md and lg widths. + static func width(_ size: String?) -> CGFloat { + switch size { + case "sm": 400 + case "lg": 720 + default: 560 + } + } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUILibrary.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUILibrary.swift new file mode 100644 index 0000000000..f3bab350c0 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUILibrary.swift @@ -0,0 +1,29 @@ +import OpenUILang +import SwiftUI + +/// react-ui's general OpenUI library rendered with native SwiftUI views. +/// Component names and arguments match `openuiLibrary` from +/// @openuidev/react-ui (see `OpenUIComponents`), and the root is `Stack`. +/// +/// It shares the chat library's views; `Stack`, `Card` (with Stack's layout +/// props) and `Modal` are its own. +public enum OpenUILibrary { + @MainActor + public static let library = SwiftUILibrary( + components: OpenUIComponents.all.map { schema in + SwiftUIComponent( + schema, + content: views[schema.name] ?? OpenUIChatLibrary.views[schema.name] ?? { _ in + AnyView(EmptyView()) + }) + }, + root: "Stack", + componentGroups: OpenUIComponents.groups) + + @MainActor + static let views: [String: ComponentContent] = [ + "Stack": { AnyView(StackView(props: $0)) }, + "Card": { AnyView(FlexCardView(props: $0)) }, + "Modal": { AnyView(ModalView(props: $0)) }, + ] +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift b/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift deleted file mode 100644 index 2d04c3ecaa..0000000000 --- a/packages/swift-lang/Tests/OpenUILangTests/ChatComponentsTests.swift +++ /dev/null @@ -1,77 +0,0 @@ -import Testing - -@testable import OpenUILang - -/// The chat component schemas must match openuiChatLibrary's Zod schemas, so -/// one backend prompt drives both the web and native renderers. -@Suite struct ChatComponentsTests { - static let tsDefs = Fixtures.schemas["chat"]["schema"]["$defs"] - static let tsSpec = Fixtures.load("chat-spec") - - @Test(arguments: ChatComponents.all.map(\.name)) - func matchesOpenUIChatLibrary(_ name: String) { - let schema = ChatComponents.all.first { $0.name == name }! - let expected = Self.tsDefs[name] - let diff = firstDifference(normalized(schema.jsonSchema), normalized(expected)) - #expect(diff == nil, "\(name): \(diff ?? "")") - // Property order is positional-argument order, so it must match exactly. - #expect( - schema.jsonSchema["properties"].objectValue?.keys == expected["properties"].objectValue?.keys) - #expect(schema.signature == Self.tsSpec["components"][name]["signature"].stringValue) - } - - @Test func coversEveryComponentInLibraryOrder() { - #expect(ChatComponents.all.map(\.name) == Self.tsSpec["components"].objectValue?.keys) - } - - @Test func libraryJSONSchemaMatchesByteForByte() { - // Key order included: top-level properties follow library order, $defs - // follow Zod's depth-first discovery order. - let library = Library( - components: ChatComponents.all.map { ComponentDefinition($0, content: ()) }, root: "Card", - componentGroups: ChatComponents.groups) - let schema = JSON.stringify(library.toJSONSchema()) - let expected = JSON.stringify(Fixtures.schemas["chat"]["schema"]) - #expect(schema == expected, "\(firstLineDifference(schema, expected) ?? "")") - } - - @Test func bindingsMatchReactiveProps() { - let reactive = Fixtures.schemas["chat"]["reactive"].objectValue ?? OpenUIObject() - for schema in ChatComponents.all { - let expected = (reactive[schema.name]?.arrayValue ?? []).compactMap(\.stringValue) - #expect(schema.props.filter(\.isBinding).map(\.name) == expected, "\(schema.name)") - } - } - - @Test func groupsMatchOpenUIChatLibrary() { - let expected = (Self.tsSpec["componentGroups"].arrayValue ?? []).map { group in - ComponentGroup( - name: group["name"].stringValue ?? "", - components: (group["components"].arrayValue ?? []).compactMap(\.stringValue), - notes: group["notes"].arrayValue?.compactMap(\.stringValue)) - } - #expect(ChatComponents.groups == expected) - } - - @Test func chatLibraryPromptWithItsOptionsMatchesLangCore() { - // What react-ui apps send: openuiChatLibrary with openuiChatPromptOptions. - let fixture = FixtureCase.all("prompts").first { $0.name == "chat-options" }! - let library = Library( - components: ChatComponents.all.map { ComponentDefinition($0, content: ()) }, root: "Card", - componentGroups: ChatComponents.groups) - let prompt = library.prompt(ChatComponents.promptOptions) - let expected = fixture.value["expected"].stringValue! - #expect(prompt == expected, "\(firstLineDifference(prompt, expected) ?? "")") - } - - @Test func chatLibraryPromptMatchesLangCore() { - // The full chat prompt (no options) is one of the prompt fixtures. - let fixture = FixtureCase.all("prompts").first { $0.name == "chat-default" }! - let library = Library( - components: ChatComponents.all.map { ComponentDefinition($0, content: ()) }, root: "Card", - componentGroups: ChatComponents.groups) - let prompt = library.prompt() - let expected = fixture.value["expected"].stringValue! - #expect(prompt == expected, "\(firstLineDifference(prompt, expected) ?? "")") - } -} diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/evaluation.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/evaluation.json index ab8a234526..10228fda12 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/evaluation.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/evaluation.json @@ -2915,6 +2915,1184 @@ "errors": [] } }, + { + "name": "openui-example-1", + "schema": "openui", + "input": "Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]", + "expected": { + "root": { + "type": "element", + "typeName": "Stack", + "props": { + "children": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Top Languages", + "size": "large-heavy" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "title" + }, + { + "type": "element", + "typeName": "Table", + "props": { + "columns": [ + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Language", + "data": [ + "Python", + "JavaScript", + "Java", + "TypeScript", + "Go" + ] + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Users (M)", + "data": [ + 15.7, + 14.2, + 12.1, + 8.5, + 5.2 + ] + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Year", + "data": [ + 1991, + 1995, + 1995, + 2012, + 2009 + ] + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tbl" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "openui-example-2", + "schema": "openui", + "input": "Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])", + "expected": { + "root": { + "type": "element", + "typeName": "Stack", + "props": { + "children": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Q4 Revenue", + "size": "large-heavy" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "title" + }, + { + "type": "element", + "typeName": "BarChart", + "props": { + "labels": [ + "Oct", + "Nov", + "Dec" + ], + "series": [ + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Product A", + "values": [ + 120, + 150, + 180 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "s1" + }, + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Product B", + "values": [ + 90, + 110, + 140 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "s2" + } + ], + "variant": "grouped" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "chart" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "openui-example-3", + "schema": "openui", + "input": "Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Stack", + "props": { + "children": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Contact Us", + "size": "large-heavy" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "title" + }, + { + "type": "element", + "typeName": "Form", + "props": { + "name": "contact", + "buttons": { + "type": "element", + "typeName": "Buttons", + "props": { + "buttons": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Submit", + "action": { + "steps": [ + { + "type": "continue_conversation", + "message": "Submit" + } + ] + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Cancel", + "action": { + "steps": [ + { + "type": "continue_conversation", + "message": "Cancel" + } + ] + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "btns" + }, + "fields": [ + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Name", + "input": { + "type": "element", + "typeName": "Input", + "props": { + "name": "name", + "placeholder": "Your name", + "type": "text", + "rules": { + "required": true, + "minLength": 2 + } + }, + "partial": false, + "hasDynamicProps": false + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "nameField" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Email", + "input": { + "type": "element", + "typeName": "Input", + "props": { + "name": "email", + "placeholder": "you@example.com", + "type": "email", + "rules": { + "required": true, + "email": true + } + }, + "partial": false, + "hasDynamicProps": false + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "emailField" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Country", + "input": { + "type": "element", + "typeName": "Select", + "props": { + "name": "country", + "items": [ + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "us", + "label": "United States" + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "uk", + "label": "United Kingdom" + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "de", + "label": "Germany" + }, + "partial": false, + "hasDynamicProps": false + } + ], + "placeholder": "Select...", + "rules": { + "required": true + } + }, + "partial": false, + "hasDynamicProps": false + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "countryField" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Message", + "input": { + "type": "element", + "typeName": "TextArea", + "props": { + "name": "message", + "placeholder": "Tell us more...", + "rows": 4, + "rules": { + "required": true, + "minLength": 10 + } + }, + "partial": false, + "hasDynamicProps": false + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "msgField" + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "form" + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "openui-example-4", + "schema": "openui", + "input": "Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]", + "expected": { + "root": { + "type": "element", + "typeName": "Stack", + "props": { + "children": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "React vs Vue", + "size": "large-heavy" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "title" + }, + { + "type": "element", + "typeName": "Tabs", + "props": { + "items": [ + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "react", + "trigger": "React", + "content": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "React is a library by Meta for building UIs." + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Callout", + "props": { + "variant": "info", + "title": "Note", + "description": "React uses JSX syntax." + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabReact" + }, + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "vue", + "trigger": "Vue", + "content": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Vue is a progressive framework by Evan You." + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Callout", + "props": { + "variant": "success", + "title": "Tip", + "description": "Vue has a gentle learning curve." + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabVue" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabs" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "openui-example-5", + "schema": "openui", + "input": "Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")", + "expected": { + "root": { + "type": "element", + "typeName": "Stack", + "props": { + "children": [ + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "This Month", + "description": "Key account metrics" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpiHeader" + }, + { + "type": "element", + "typeName": "SnippetCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "revenue", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "circle-dollar-sign", + "category": "finance" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Revenue", + "subtitle": "Month to date", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "$48,200", + "subtext": "+8.1%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1" + }, + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "active-users", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "users", + "category": "people" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Active Users", + "subtitle": "This month", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "1,204", + "subtext": "+3.4%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2" + }, + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "churn", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "user-minus", + "category": "people" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Churn", + "subtitle": "This month", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "1.8%", + "subtext": "-0.3%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3" + } + ], + "layout": "grid", + "responsive": true + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpiBlock" + }, + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "Top Products", + "description": "By units sold" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "productsHeader" + }, + { + "type": "element", + "typeName": "CompositeCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "CompositeCardItem", + "props": { + "id": "widget-pro", + "header": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "package", + "category": "shopping" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "p1icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Widget Pro", + "subtitle": "Best seller", + "bold": true, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "p1header" + }, + "body": [ + { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "2,410 units", + "subtext": "Sold this month", + "trend": { + "direction": "up", + "value": 12 + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "p1body" + } + ], + "footer": { + "price": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "$29.00", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false + }, + "button": { + "type": "element", + "typeName": "Button", + "props": { + "label": "View Details", + "action": { + "steps": [ + { + "type": "continue_conversation", + "message": "Show details for Widget Pro" + } + ] + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "p1btn" + } + } + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "p1" + }, + { + "type": "element", + "typeName": "CompositeCardItem", + "props": { + "id": "widget-mini", + "header": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "box", + "category": "shopping" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "p2icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Widget Mini", + "subtitle": "New arrival", + "bold": true, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "p2header" + }, + "body": [ + { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "980 units", + "subtext": "Sold this month", + "trend": { + "direction": "up", + "value": 4 + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "p2body" + } + ], + "footer": { + "price": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "$14.00", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false + }, + "button": { + "type": "element", + "typeName": "Button", + "props": { + "label": "View Details", + "action": { + "steps": [ + { + "type": "continue_conversation", + "message": "Show details for Widget Mini" + } + ] + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "p2btn" + } + } + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "p2" + } + ], + "layout": "grid", + "responsive": true + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "productCards" + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, + { + "name": "openui-example-6", + "schema": "openui", + "input": "Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Stack", + "props": { + "children": [ + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "Team Roster", + "description": "Click a cell to edit" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tableHeader" + }, + { + "type": "element", + "typeName": "EditableTable", + "props": { + "name": "roster", + "columns": [ + { + "type": "text", + "key": "name", + "header": "Name" + }, + { + "type": "select", + "key": "role", + "header": "Role", + "options": [ + { + "value": "eng", + "label": "Engineering" + }, + { + "value": "design", + "label": "Design" + } + ] + }, + { + "type": "date-single", + "key": "start", + "header": "Start Date" + } + ], + "data": [ + { + "id": "1", + "values": [ + "Alex Kim", + "eng", + "2024-01-15" + ] + }, + { + "id": "2", + "values": [ + "Jamie Lee", + "design", + "2024-03-02" + ] + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "editTable" + }, + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "Preferences", + "description": "Tell us how you like to work" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "formHeader" + }, + { + "type": "element", + "typeName": "Form", + "props": { + "name": "prefs", + "buttons": { + "type": "element", + "typeName": "Buttons", + "props": { + "buttons": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Save", + "action": { + "steps": [ + { + "type": "continue_conversation", + "message": "Save preferences" + } + ] + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "formButtons" + }, + "fields": [ + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Working Style", + "input": { + "type": "element", + "typeName": "OptionCards", + "props": { + "name": "style", + "type": "single", + "items": [ + { + "type": "element", + "typeName": "OptionCard", + "props": { + "value": "focused", + "title": "Deep Focus", + "subtitle": "Long uninterrupted blocks", + "topContent": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "target", + "category": "tools" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "style1icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "style1" + }, + { + "type": "element", + "typeName": "OptionCard", + "props": { + "value": "collab", + "title": "Collaborative", + "subtitle": "Frequent pairing and syncs", + "topContent": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "users", + "category": "people" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "style2icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "style2" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "styleCards" + }, + "hint": "Pick the one that fits best" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fc1" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Tools", + "input": { + "type": "element", + "typeName": "Chips", + "props": { + "name": "tools", + "type": "multiple", + "items": [ + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "figma", + "label": "Figma", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "figma", + "category": "design" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tool1icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tool1" + }, + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "slack", + "label": "Slack", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "message-square", + "category": "communication" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tool2icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tool2" + }, + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "notion", + "label": "Notion", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "notebook", + "category": "text" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tool3icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tool3" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "toolChips" + }, + "hint": "Select all that apply" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fc2" + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "prefsForm" + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "errors": [] + } + }, { "name": "operators", "schema": "test", diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/openui-spec.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/openui-spec.json new file mode 100644 index 0000000000..ce2254ee70 --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/openui-spec.json @@ -0,0 +1,4752 @@ +{ + "root": "Stack", + "components": { + "Card": { + "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)", + "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." + }, + "CardHeader": { + "signature": "CardHeader(title?: string, subtitle?: string)", + "description": "Header with optional title and subtitle" + }, + "TextContent": { + "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "MarkDownRenderer": { + "signature": "MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")", + "description": "Renders markdown text with optional container variant" + }, + "Callout": { + "signature": "Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)", + "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." + }, + "TextCallout": { + "signature": "TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)", + "description": "Text callout with variant, title, and description" + }, + "Image": { + "signature": "Image(alt: string, src?: string)", + "description": "Image with alt text and optional URL" + }, + "ImageBlock": { + "signature": "ImageBlock(src: string, alt?: string)", + "description": "Image block with loading state" + }, + "ImageGallery": { + "signature": "ImageGallery(images: {src: string, alt?: string, details?: string}[])", + "description": "Gallery grid of images with modal preview" + }, + "CodeBlock": { + "signature": "CodeBlock(language: string, codeString: string)", + "description": "Syntax-highlighted code block" + }, + "InlineHeader": { + "signature": "InlineHeader(heading: string, description?: string)", + "description": "Compact section heading with an optional one-line description, for use inside cards." + }, + "Table": { + "signature": "Table(columns: Col[])", + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", + "description": "Column definition — holds label + data array" + }, + "EditableTable": { + "signature": "EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])", + "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" + }, + "BarChart": { + "signature": "BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Vertical bars; use for comparing values across categories with one or more series" + }, + "LineChart": { + "signature": "LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Lines over categories; use for trends and continuous data over time" + }, + "AreaChart": { + "signature": "AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Filled area under lines; use for cumulative totals or volume trends over time" + }, + "RadarChart": { + "signature": "RadarChart(labels: string[], series: Series[])", + "description": "Spider/web chart; use for comparing multiple variables across one or more entities" + }, + "HorizontalBarChart": { + "signature": "HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)", + "description": "Horizontal bars; prefer when category labels are long or for ranked lists" + }, + "Series": { + "signature": "Series(category: string, values: number[])", + "description": "One data series" + }, + "PieChart": { + "signature": "PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")", + "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" + }, + "RadialChart": { + "signature": "RadialChart(labels: string[], values: number[])", + "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" + }, + "SingleStackedBarChart": { + "signature": "SingleStackedBarChart(labels: string[], values: number[])", + "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" + }, + "Slice": { + "signature": "Slice(category: string, value: number)", + "description": "One slice with label and numeric value" + }, + "ScatterChart": { + "signature": "ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)", + "description": "X/Y scatter plot; use for correlations, distributions, and clustering" + }, + "ScatterSeries": { + "signature": "ScatterSeries(name: string, points: Point[])", + "description": "Named dataset" + }, + "Point": { + "signature": "Point(x: number, y: number, z?: number)", + "description": "Data point with numeric coordinates" + }, + "Form": { + "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", + "description": "Form container with fields and explicit action buttons" + }, + "FormControl": { + "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", + "description": "Field with label, input component, and optional hint text" + }, + "Label": { + "signature": "Label(text: string)", + "description": "Text label" + }, + "Input": { + "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "TextArea": { + "signature": "TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Select": { + "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", + "description": "" + }, + "SelectItem": { + "signature": "SelectItem(value: string, label: string)", + "description": "Option for Select" + }, + "DatePicker": { + "signature": "DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Slider": { + "signature": "Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "Numeric slider input; supports continuous and discrete (stepped) variants" + }, + "CheckBoxGroup": { + "signature": "CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)", + "description": "" + }, + "CheckBoxItem": { + "signature": "CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)", + "description": "" + }, + "RadioGroup": { + "signature": "RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "RadioItem": { + "signature": "RadioItem(label: string, description: string, value: string)", + "description": "" + }, + "SwitchGroup": { + "signature": "SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)", + "description": "Group of switch toggles" + }, + "SwitchItem": { + "signature": "SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)", + "description": "Individual switch toggle" + }, + "ChipItem": { + "signature": "ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)", + "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." + }, + "Chips": { + "signature": "Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", + "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." + }, + "OptionCard": { + "signature": "OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)", + "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." + }, + "OptionCards": { + "signature": "OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", + "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." + }, + "Button": { + "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", + "description": "Clickable button" + }, + "Buttons": { + "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "IconButton": { + "signature": "IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")", + "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." + }, + "Stack": { + "signature": "Stack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)", + "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." + }, + "Tabs": { + "signature": "Tabs(items: TabItem[])", + "description": "Tabbed container" + }, + "TabItem": { + "signature": "TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])", + "description": "value is unique id, trigger is tab label, content is array of components" + }, + "Accordion": { + "signature": "Accordion(items: AccordionItem[])", + "description": "Collapsible sections" + }, + "AccordionItem": { + "signature": "AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])", + "description": "value is unique id, trigger is section title" + }, + "Steps": { + "signature": "Steps(items: StepsItem[])", + "description": "Step-by-step guide" + }, + "StepsItem": { + "signature": "StepsItem(title: string, details: string)", + "description": "title and details text for one step" + }, + "Carousel": { + "signature": "Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\")", + "description": "Horizontal scrollable carousel" + }, + "Separator": { + "signature": "Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)", + "description": "Visual divider between content sections" + }, + "TagBlock": { + "signature": "TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")", + "description": "tags is an array of strings; optional size sm | md | lg" + }, + "Tag": { + "signature": "Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")", + "description": "Styled tag/badge with optional Icon and variant" + }, + "Icon": { + "signature": "Icon(name: string, category?: string)", + "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." + }, + "EntityList": { + "signature": "EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})", + "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." + }, + "ListBlock": { + "signature": "ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")", + "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." + }, + "ListItem": { + "signature": "ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)", + "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." + }, + "Text": { + "signature": "Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", + "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "BoldText": { + "signature": "BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", + "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "IconText": { + "signature": "IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")", + "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." + }, + "ImageText": { + "signature": "ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)", + "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." + }, + "ImageTextLarge": { + "signature": "ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)", + "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." + }, + "MetricIndicatorInline": { + "signature": "MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})", + "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." + }, + "MetricIndicatorWithStrikethrough": { + "signature": "MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})", + "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." + }, + "SnippetCardItem": { + "signature": "SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)", + "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." + }, + "SnippetCardBlock": { + "signature": "SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." + }, + "OverviewCardItem": { + "signature": "OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)", + "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." + }, + "OverviewCardBlock": { + "signature": "OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." + }, + "ContextCardItem": { + "signature": "ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)", + "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." + }, + "ContextCardBlock": { + "signature": "ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." + }, + "CompositeCardItem": { + "signature": "CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})", + "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." + }, + "CompositeCardBlock": { + "signature": "CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." + }, + "VisualCardItem": { + "signature": "VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)", + "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." + }, + "VisualCardBlock": { + "signature": "VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." + }, + "Modal": { + "signature": "Modal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\")", + "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." + } + }, + "componentGroups": [ + { + "name": "Layout", + "components": [ + "Stack", + "Tabs", + "TabItem", + "Accordion", + "AccordionItem", + "Steps", + "StepsItem", + "Carousel", + "Separator", + "Modal" + ], + "notes": [ + "- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.", + "- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.", + "- Use nested Stacks when you need explicit rows/sections.", + "- Show/hide sections: $editId != \"\" ? Card([editForm]) : null", + "- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.", + "- Use Tabs for alternative views (chart types, data sections) — no $variable needed", + "- Shared filter across Tabs: same $days binding in Query args works across all TabItems" + ] + }, + { + "name": "Content", + "components": [ + "Card", + "CardHeader", + "TextContent", + "MarkDownRenderer", + "Callout", + "TextCallout", + "Image", + "ImageBlock", + "ImageGallery", + "CodeBlock", + "InlineHeader" + ], + "notes": [ + "- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).", + "- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.", + "- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null", + "- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])" + ] + }, + { + "name": "Tables", + "components": [ + "Table", + "Col", + "EditableTable" + ], + "notes": [ + "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", + "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.", + "- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName", + "- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))", + "- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))", + "- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data", + "- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input", + "- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts", + "- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")" + ] + }, + { + "name": "Charts (2D)", + "components": [ + "BarChart", + "LineChart", + "AreaChart", + "RadarChart", + "HorizontalBarChart", + "Series" + ], + "notes": [ + "- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])", + "- Use Cards to wrap charts with CardHeader for titled sections", + "- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data", + "- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])" + ] + }, + { + "name": "Charts (1D)", + "components": [ + "PieChart", + "RadialChart", + "SingleStackedBarChart", + "Slice" + ], + "notes": [ + "- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:", + "- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`", + "- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`" + ] + }, + { + "name": "Charts (Scatter)", + "components": [ + "ScatterChart", + "ScatterSeries", + "Point" + ] + }, + { + "name": "Forms", + "components": [ + "Form", + "FormControl", + "Label", + "Input", + "TextArea", + "Select", + "SelectItem", + "DatePicker", + "Slider", + "CheckBoxGroup", + "CheckBoxItem", + "RadioGroup", + "RadioItem", + "SwitchGroup", + "SwitchItem", + "Chips", + "ChipItem", + "OptionCards", + "OptionCard" + ], + "notes": [ + "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", + "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", + "- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.", + "- NEVER nest Form inside Form — each Form should be a standalone container.", + "- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.", + "- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}", + "- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric", + "- The renderer shows error messages automatically — do NOT generate error text in the UI", + "- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField", + "- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal." + ] + }, + { + "name": "Buttons", + "components": [ + "Button", + "Buttons", + "IconButton" + ], + "notes": [ + "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.", + "- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))" + ] + }, + { + "name": "Data Display", + "components": [ + "TagBlock", + "Tag", + "Icon", + "EntityList", + "ListBlock", + "ListItem" + ], + "notes": [ + "- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")", + "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.", + "- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional." + ] + }, + { + "name": "Cards", + "components": [ + "SnippetCardBlock", + "SnippetCardItem", + "OverviewCardBlock", + "OverviewCardItem", + "ContextCardBlock", + "ContextCardItem", + "CompositeCardBlock", + "CompositeCardItem", + "VisualCardBlock", + "VisualCardItem", + "Text", + "BoldText", + "IconText", + "ImageText", + "ImageTextLarge", + "MetricIndicatorInline", + "MetricIndicatorWithStrikethrough" + ], + "notes": [ + "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", + "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", + "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", + "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", + "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", + "- VisualCardItem: image-first card with a BoldText body and optional Tag.", + "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card." + ] + } + ], + "schema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "Card": { + "$ref": "#/$defs/Card" + }, + "CardHeader": { + "$ref": "#/$defs/CardHeader" + }, + "TextContent": { + "$ref": "#/$defs/TextContent" + }, + "MarkDownRenderer": { + "$ref": "#/$defs/MarkDownRenderer" + }, + "Callout": { + "$ref": "#/$defs/Callout" + }, + "TextCallout": { + "$ref": "#/$defs/TextCallout" + }, + "Image": { + "$ref": "#/$defs/Image" + }, + "ImageBlock": { + "$ref": "#/$defs/ImageBlock" + }, + "ImageGallery": { + "$ref": "#/$defs/ImageGallery" + }, + "CodeBlock": { + "$ref": "#/$defs/CodeBlock" + }, + "InlineHeader": { + "$ref": "#/$defs/InlineHeader" + }, + "Table": { + "$ref": "#/$defs/Table" + }, + "Col": { + "$ref": "#/$defs/Col" + }, + "EditableTable": { + "$ref": "#/$defs/EditableTable" + }, + "BarChart": { + "$ref": "#/$defs/BarChart" + }, + "LineChart": { + "$ref": "#/$defs/LineChart" + }, + "AreaChart": { + "$ref": "#/$defs/AreaChart" + }, + "RadarChart": { + "$ref": "#/$defs/RadarChart" + }, + "HorizontalBarChart": { + "$ref": "#/$defs/HorizontalBarChart" + }, + "Series": { + "$ref": "#/$defs/Series" + }, + "PieChart": { + "$ref": "#/$defs/PieChart" + }, + "RadialChart": { + "$ref": "#/$defs/RadialChart" + }, + "SingleStackedBarChart": { + "$ref": "#/$defs/SingleStackedBarChart" + }, + "Slice": { + "$ref": "#/$defs/Slice" + }, + "ScatterChart": { + "$ref": "#/$defs/ScatterChart" + }, + "ScatterSeries": { + "$ref": "#/$defs/ScatterSeries" + }, + "Point": { + "$ref": "#/$defs/Point" + }, + "Form": { + "$ref": "#/$defs/Form" + }, + "FormControl": { + "$ref": "#/$defs/FormControl" + }, + "Label": { + "$ref": "#/$defs/Label" + }, + "Input": { + "$ref": "#/$defs/Input" + }, + "TextArea": { + "$ref": "#/$defs/TextArea" + }, + "Select": { + "$ref": "#/$defs/Select" + }, + "SelectItem": { + "$ref": "#/$defs/SelectItem" + }, + "DatePicker": { + "$ref": "#/$defs/DatePicker" + }, + "Slider": { + "$ref": "#/$defs/Slider" + }, + "CheckBoxGroup": { + "$ref": "#/$defs/CheckBoxGroup" + }, + "CheckBoxItem": { + "$ref": "#/$defs/CheckBoxItem" + }, + "RadioGroup": { + "$ref": "#/$defs/RadioGroup" + }, + "RadioItem": { + "$ref": "#/$defs/RadioItem" + }, + "SwitchGroup": { + "$ref": "#/$defs/SwitchGroup" + }, + "SwitchItem": { + "$ref": "#/$defs/SwitchItem" + }, + "ChipItem": { + "$ref": "#/$defs/ChipItem" + }, + "Chips": { + "$ref": "#/$defs/Chips" + }, + "OptionCard": { + "$ref": "#/$defs/OptionCard" + }, + "OptionCards": { + "$ref": "#/$defs/OptionCards" + }, + "Button": { + "$ref": "#/$defs/Button" + }, + "Buttons": { + "$ref": "#/$defs/Buttons" + }, + "IconButton": { + "$ref": "#/$defs/IconButton" + }, + "Stack": { + "$ref": "#/$defs/Stack" + }, + "Tabs": { + "$ref": "#/$defs/Tabs" + }, + "TabItem": { + "$ref": "#/$defs/TabItem" + }, + "Accordion": { + "$ref": "#/$defs/Accordion" + }, + "AccordionItem": { + "$ref": "#/$defs/AccordionItem" + }, + "Steps": { + "$ref": "#/$defs/Steps" + }, + "StepsItem": { + "$ref": "#/$defs/StepsItem" + }, + "Carousel": { + "$ref": "#/$defs/Carousel" + }, + "Separator": { + "$ref": "#/$defs/Separator" + }, + "TagBlock": { + "$ref": "#/$defs/TagBlock" + }, + "Tag": { + "$ref": "#/$defs/Tag" + }, + "Icon": { + "$ref": "#/$defs/Icon" + }, + "EntityList": { + "$ref": "#/$defs/EntityList" + }, + "ListBlock": { + "$ref": "#/$defs/ListBlock" + }, + "ListItem": { + "$ref": "#/$defs/ListItem" + }, + "Text": { + "$ref": "#/$defs/Text" + }, + "BoldText": { + "$ref": "#/$defs/BoldText" + }, + "IconText": { + "$ref": "#/$defs/IconText" + }, + "ImageText": { + "$ref": "#/$defs/ImageText" + }, + "ImageTextLarge": { + "$ref": "#/$defs/ImageTextLarge" + }, + "MetricIndicatorInline": { + "$ref": "#/$defs/MetricIndicatorInline" + }, + "MetricIndicatorWithStrikethrough": { + "$ref": "#/$defs/MetricIndicatorWithStrikethrough" + }, + "SnippetCardItem": { + "$ref": "#/$defs/SnippetCardItem" + }, + "SnippetCardBlock": { + "$ref": "#/$defs/SnippetCardBlock" + }, + "OverviewCardItem": { + "$ref": "#/$defs/OverviewCardItem" + }, + "OverviewCardBlock": { + "$ref": "#/$defs/OverviewCardBlock" + }, + "ContextCardItem": { + "$ref": "#/$defs/ContextCardItem" + }, + "ContextCardBlock": { + "$ref": "#/$defs/ContextCardBlock" + }, + "CompositeCardItem": { + "$ref": "#/$defs/CompositeCardItem" + }, + "CompositeCardBlock": { + "$ref": "#/$defs/CompositeCardBlock" + }, + "VisualCardItem": { + "$ref": "#/$defs/VisualCardItem" + }, + "VisualCardBlock": { + "$ref": "#/$defs/VisualCardBlock" + }, + "Modal": { + "$ref": "#/$defs/Modal" + } + }, + "required": [ + "Card", + "CardHeader", + "TextContent", + "MarkDownRenderer", + "Callout", + "TextCallout", + "Image", + "ImageBlock", + "ImageGallery", + "CodeBlock", + "InlineHeader", + "Table", + "Col", + "EditableTable", + "BarChart", + "LineChart", + "AreaChart", + "RadarChart", + "HorizontalBarChart", + "Series", + "PieChart", + "RadialChart", + "SingleStackedBarChart", + "Slice", + "ScatterChart", + "ScatterSeries", + "Point", + "Form", + "FormControl", + "Label", + "Input", + "TextArea", + "Select", + "SelectItem", + "DatePicker", + "Slider", + "CheckBoxGroup", + "CheckBoxItem", + "RadioGroup", + "RadioItem", + "SwitchGroup", + "SwitchItem", + "ChipItem", + "Chips", + "OptionCard", + "OptionCards", + "Button", + "Buttons", + "IconButton", + "Stack", + "Tabs", + "TabItem", + "Accordion", + "AccordionItem", + "Steps", + "StepsItem", + "Carousel", + "Separator", + "TagBlock", + "Tag", + "Icon", + "EntityList", + "ListBlock", + "ListItem", + "Text", + "BoldText", + "IconText", + "ImageText", + "ImageTextLarge", + "MetricIndicatorInline", + "MetricIndicatorWithStrikethrough", + "SnippetCardItem", + "SnippetCardBlock", + "OverviewCardItem", + "OverviewCardBlock", + "ContextCardItem", + "ContextCardBlock", + "CompositeCardItem", + "CompositeCardBlock", + "VisualCardItem", + "VisualCardBlock", + "Modal" + ], + "additionalProperties": false, + "$defs": { + "Card": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + }, + { + "$ref": "#/$defs/Tabs" + }, + { + "$ref": "#/$defs/Carousel" + }, + { + "$ref": "#/$defs/Stack" + } + ] + } + }, + "variant": { + "type": "string", + "enum": [ + "card", + "sunk", + "clear" + ] + }, + "direction": { + "type": "string", + "enum": [ + "row", + "column" + ] + }, + "gap": { + "type": "string", + "enum": [ + "none", + "xs", + "s", + "m", + "l", + "xl", + "2xl" + ] + }, + "align": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "stretch", + "baseline" + ] + }, + "justify": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "between", + "around", + "evenly" + ] + }, + "wrap": { + "type": "boolean" + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." + }, + "TextContent": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "size": { + "type": "string", + "enum": [ + "small", + "default", + "large", + "small-heavy", + "large-heavy" + ] + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "MarkDownRenderer": { + "type": "object", + "properties": { + "textMarkdown": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": [ + "clear", + "card", + "sunk" + ] + } + }, + "required": [ + "textMarkdown" + ], + "additionalProperties": false, + "description": "Renders markdown text with optional container variant" + }, + "CardHeader": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + } + }, + "additionalProperties": false, + "description": "Header with optional title and subtitle" + }, + "Callout": { + "type": "object", + "properties": { + "variant": { + "type": "string", + "enum": [ + "info", + "warning", + "error", + "success", + "neutral" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "visible": { + "type": "boolean" + } + }, + "required": [ + "variant", + "title", + "description" + ], + "additionalProperties": false, + "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." + }, + "TextCallout": { + "type": "object", + "properties": { + "variant": { + "type": "string", + "enum": [ + "neutral", + "info", + "warning", + "success", + "danger" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false, + "description": "Text callout with variant, title, and description" + }, + "CodeBlock": { + "type": "object", + "properties": { + "language": { + "type": "string" + }, + "codeString": { + "type": "string" + } + }, + "required": [ + "language", + "codeString" + ], + "additionalProperties": false, + "description": "Syntax-highlighted code block" + }, + "Image": { + "type": "object", + "properties": { + "alt": { + "type": "string" + }, + "src": { + "type": "string" + } + }, + "required": [ + "alt" + ], + "additionalProperties": false, + "description": "Image with alt text and optional URL" + }, + "ImageBlock": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + } + }, + "required": [ + "src" + ], + "additionalProperties": false, + "description": "Image block with loading state" + }, + "ImageGallery": { + "type": "object", + "properties": { + "images": { + "type": "array", + "items": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "details": { + "type": "string" + } + }, + "required": [ + "src" + ], + "additionalProperties": false + } + } + }, + "required": [ + "images" + ], + "additionalProperties": false, + "description": "Gallery grid of images with modal preview" + }, + "Separator": { + "type": "object", + "properties": { + "orientation": { + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + }, + "decorative": { + "type": "boolean" + } + }, + "additionalProperties": false, + "description": "Visual divider between content sections" + }, + "HorizontalBarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "grouped", + "stacked" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Horizontal bars; prefer when category labels are long or for ranked lists" + }, + "Series": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "category", + "values" + ], + "additionalProperties": false, + "description": "One data series" + }, + "RadarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Spider/web chart; use for comparing multiple variables across one or more entities" + }, + "PieChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + }, + "variant": { + "type": "string", + "enum": [ + "pie", + "donut" + ] + }, + "appearance": { + "type": "string", + "enum": [ + "circular", + "semiCircular" + ] + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" + }, + "RadialChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" + }, + "SingleStackedBarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" + }, + "ScatterChart": { + "type": "object", + "properties": { + "datasets": { + "type": "array", + "items": { + "$ref": "#/$defs/ScatterSeries" + } + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + } + }, + "required": [ + "datasets" + ], + "additionalProperties": false, + "description": "X/Y scatter plot; use for correlations, distributions, and clustering" + }, + "ScatterSeries": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "points": { + "type": "array", + "items": { + "$ref": "#/$defs/Point" + } + } + }, + "required": [ + "name", + "points" + ], + "additionalProperties": false, + "description": "Named dataset" + }, + "Point": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "z": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ], + "additionalProperties": false, + "description": "Data point with numeric coordinates" + }, + "AreaChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "linear", + "natural", + "step" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Filled area under lines; use for cumulative totals or volume trends over time" + }, + "BarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "grouped", + "stacked" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Vertical bars; use for comparing values across categories with one or more series" + }, + "LineChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "linear", + "natural", + "step" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Lines over categories; use for trends and continuous data over time" + }, + "Table": { + "type": "object", + "properties": { + "columns": { + "type": "array", + "items": { + "$ref": "#/$defs/Col" + } + } + }, + "required": [ + "columns" + ], + "additionalProperties": false, + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "data": {}, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "action" + ] + } + }, + "required": [ + "label", + "data" + ], + "additionalProperties": false, + "description": "Column definition — holds label + data array" + }, + "TagBlock": { + "type": "object", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "tags" + ], + "additionalProperties": false, + "description": "tags is an array of strings; optional size sm | md | lg" + }, + "Form": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "buttons": { + "$ref": "#/$defs/Buttons" + }, + "fields": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/FormControl" + } + } + }, + "required": [ + "name", + "buttons", + "fields" + ], + "additionalProperties": false, + "description": "Form container with fields and explicit action buttons" + }, + "Buttons": { + "type": "object", + "properties": { + "buttons": { + "type": "array", + "items": { + "$ref": "#/$defs/Button" + } + }, + "direction": { + "type": "string", + "enum": [ + "row", + "column" + ] + } + }, + "required": [ + "buttons" + ], + "additionalProperties": false, + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "Button": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "variant": { + "type": "string", + "enum": [ + "primary", + "secondary", + "tertiary" + ] + }, + "type": { + "type": "string", + "enum": [ + "normal", + "destructive" + ] + }, + "size": { + "type": "string", + "enum": [ + "extra-small", + "small", + "medium", + "large" + ] + } + }, + "required": [ + "label" + ], + "additionalProperties": false, + "description": "Clickable button" + }, + "FormControl": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "input": { + "anyOf": [ + { + "$ref": "#/$defs/Input" + }, + { + "$ref": "#/$defs/TextArea" + }, + { + "$ref": "#/$defs/Select" + }, + { + "$ref": "#/$defs/DatePicker" + }, + { + "$ref": "#/$defs/Slider" + }, + { + "$ref": "#/$defs/CheckBoxGroup" + }, + { + "$ref": "#/$defs/RadioGroup" + }, + { + "$ref": "#/$defs/Chips" + }, + { + "$ref": "#/$defs/OptionCards" + } + ] + }, + "hint": { + "type": "string" + } + }, + "required": [ + "label", + "input" + ], + "additionalProperties": false, + "description": "Field with label, input component, and optional hint text" + }, + "Input": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "placeholder": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "text", + "email", + "password", + "number", + "url" + ] + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "TextArea": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "placeholder": { + "type": "string" + }, + "rows": { + "type": "number" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "Select": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/SelectItem" + } + }, + "placeholder": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + }, + "size": { + "type": "string", + "enum": [ + "small", + "medium", + "large" + ] + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "SelectItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false, + "description": "Option for Select" + }, + "DatePicker": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "mode": { + "type": "string", + "enum": [ + "single", + "range" + ] + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": {} + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "Slider": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": [ + "continuous", + "discrete" + ] + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "step": { + "type": "number" + }, + "defaultValue": { + "type": "array", + "items": { + "type": "number" + } + }, + "label": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "name", + "variant", + "min", + "max" + ], + "additionalProperties": false, + "description": "Numeric slider input; supports continuous and discrete (stepped) variants" + }, + "CheckBoxGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/CheckBoxItem" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "CheckBoxItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "defaultChecked": { + "type": "boolean" + } + }, + "required": [ + "label", + "description", + "name" + ], + "additionalProperties": false + }, + "RadioGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/RadioItem" + } + }, + "defaultValue": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "RadioItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "description", + "value" + ], + "additionalProperties": false + }, + "Chips": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "default": "multiple", + "type": "string", + "enum": [ + "single", + "multiple" + ] + }, + "items": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/ChipItem" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "defaultValue": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "name", + "type", + "items" + ], + "additionalProperties": false, + "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." + }, + "ChipItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "disabled": { + "type": "boolean" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false, + "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." + }, + "Icon": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "category": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false, + "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." + }, + "OptionCards": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "default": "single", + "type": "string", + "enum": [ + "single", + "multiple" + ] + }, + "items": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/OptionCard" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "defaultValue": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "name", + "type", + "items" + ], + "additionalProperties": false, + "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." + }, + "OptionCard": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "topContent": { + "anyOf": [ + { + "$ref": "#/$defs/Icon" + }, + { + "$ref": "#/$defs/Image" + } + ] + }, + "disabled": { + "type": "boolean" + } + }, + "required": [ + "value", + "title" + ], + "additionalProperties": false, + "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." + }, + "IconButton": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "variant": { + "type": "string", + "enum": [ + "primary", + "secondary", + "tertiary" + ] + }, + "size": { + "type": "string", + "enum": [ + "extra-small", + "small", + "medium", + "large" + ] + }, + "shape": { + "type": "string", + "enum": [ + "square", + "circle" + ] + } + }, + "required": [ + "name", + "icon" + ], + "additionalProperties": false, + "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." + }, + "Steps": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/StepsItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Step-by-step guide" + }, + "StepsItem": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "details": { + "type": "string" + } + }, + "required": [ + "title", + "details" + ], + "additionalProperties": false, + "description": "title and details text for one step" + }, + "InlineHeader": { + "type": "object", + "properties": { + "heading": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "heading" + ], + "additionalProperties": false, + "description": "Compact section heading with an optional one-line description, for use inside cards." + }, + "EntityList": { + "type": "object", + "properties": { + "rows": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + } + }, + "size": { + "default": "default", + "type": "string", + "enum": [ + "small", + "default" + ] + }, + "header": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + }, + "footer": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + } + }, + "required": [ + "rows", + "size" + ], + "additionalProperties": false, + "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." + }, + "EditableTable": { + "type": "object", + "properties": { + "name": { + "default": "", + "type": "string" + }, + "columns": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "text", + "number", + "date-single", + "select", + "url" + ] + }, + "key": { + "default": "default", + "type": "string" + }, + "header": { + "default": "", + "type": "string" + }, + "width": { + "type": "number" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false + } + } + }, + "required": [ + "type", + "key", + "header" + ], + "additionalProperties": false + } + }, + "data": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + } + }, + "required": [ + "id", + "values" + ], + "additionalProperties": false + } + } + }, + "required": [ + "name", + "columns", + "data" + ], + "additionalProperties": false, + "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" + }, + "SnippetCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/SnippetCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." + }, + "SnippetCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "lhs": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + } + ] + }, + "rhs": { + "anyOf": [ + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/BoldText" + } + ] + } + }, + "required": [ + "lhs" + ], + "additionalProperties": false, + "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." + }, + "IconText": { + "type": "object", + "properties": { + "icon": { + "$ref": "#/$defs/Icon" + }, + "iconVariant": { + "default": "neutral", + "type": "string", + "enum": [ + "neutral", + "info", + "success", + "warning", + "danger", + "inverted", + "filled", + "soft" + ] + }, + "iconSize": { + "default": "m", + "type": "string", + "enum": [ + "xs", + "s", + "m", + "l", + "xl", + "sm", + "md", + "lg" + ] + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + }, + "layout": { + "default": "horizontal", + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + } + }, + "required": [ + "icon", + "iconVariant", + "iconSize", + "title", + "bold", + "layout" + ], + "additionalProperties": false, + "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." + }, + "ImageText": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + }, + "layout": { + "default": "horizontal", + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + }, + "imageSize": { + "type": "number" + } + }, + "required": [ + "src", + "title", + "bold", + "layout" + ], + "additionalProperties": false, + "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." + }, + "Text": { + "type": "object", + "properties": { + "variant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + }, + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "subtextVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number", + "metric" + ] + }, + "size": { + "default": "sm", + "type": "string", + "enum": [ + "xs", + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "variant", + "value", + "subtextVariant", + "size" + ], + "additionalProperties": false, + "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "BoldText": { + "type": "object", + "properties": { + "variant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + }, + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "subtextVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number", + "metric" + ] + }, + "size": { + "default": "sm", + "type": "string", + "enum": [ + "xs", + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "variant", + "value", + "subtextVariant", + "size" + ], + "additionalProperties": false, + "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "OverviewCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/OverviewCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." + }, + "OverviewCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "top": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + }, + { + "$ref": "#/$defs/Text" + } + ] + }, + "bottom": { + "$ref": "#/$defs/MetricIndicatorInline" + } + }, + "required": [ + "top" + ], + "additionalProperties": false, + "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." + }, + "MetricIndicatorInline": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "trend": { + "type": "object", + "properties": { + "direction": { + "type": "string", + "enum": [ + "up", + "down" + ] + }, + "value": { + "type": "number" + } + }, + "required": [ + "direction", + "value" + ], + "additionalProperties": false + } + }, + "required": [ + "value" + ], + "additionalProperties": false, + "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." + }, + "ContextCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/ContextCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." + }, + "ContextCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/Tag" + } + ] + }, + "body": { + "type": "string" + }, + "bgColor": { + "type": "string", + "enum": [ + "gray" + ] + }, + "bgImageSrc": { + "type": "string" + }, + "bgImageAlt": { + "type": "string" + } + }, + "required": [ + "title" + ], + "additionalProperties": false, + "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." + }, + "Tag": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + }, + "variant": { + "type": "string", + "enum": [ + "neutral", + "info", + "success", + "warning", + "danger" + ] + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Styled tag/badge with optional Icon and variant" + }, + "CompositeCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/CompositeCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." + }, + "CompositeCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "header": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + }, + { + "$ref": "#/$defs/ImageTextLarge" + }, + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/Image" + } + ] + }, + "body": { + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/BoldText" + }, + { + "$ref": "#/$defs/MetricIndicatorInline" + }, + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/ListBlock" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/EntityList" + } + ] + } + }, + "footer": { + "type": "object", + "properties": { + "price": { + "anyOf": [ + { + "$ref": "#/$defs/BoldText" + }, + { + "$ref": "#/$defs/MetricIndicatorWithStrikethrough" + } + ] + }, + "button": { + "$ref": "#/$defs/Button" + } + }, + "additionalProperties": false + } + }, + "required": [ + "body" + ], + "additionalProperties": false, + "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." + }, + "ImageTextLarge": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + } + }, + "required": [ + "src", + "title", + "bold" + ], + "additionalProperties": false, + "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." + }, + "ListBlock": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/ListItem" + } + }, + "variant": { + "type": "string", + "enum": [ + "number", + "image" + ] + }, + "size": { + "type": "string", + "enum": [ + "default", + "small" + ] + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." + }, + "ListItem": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "image": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + } + }, + "required": [ + "src", + "alt" + ], + "additionalProperties": false + }, + "actionLabel": { + "type": "string" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "title" + ], + "additionalProperties": false, + "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." + }, + "MetricIndicatorWithStrikethrough": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "previousValue": { + "type": "string" + }, + "trend": { + "type": "object", + "properties": { + "direction": { + "type": "string", + "enum": [ + "up", + "down" + ] + }, + "value": { + "type": "number" + } + }, + "required": [ + "direction", + "value" + ], + "additionalProperties": false + } + }, + "required": [ + "value" + ], + "additionalProperties": false, + "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." + }, + "VisualCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/VisualCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." + }, + "VisualCardItem": { + "type": "object", + "properties": { + "body": { + "$ref": "#/$defs/BoldText" + }, + "id": { + "type": "string" + }, + "bgImageSrc": { + "type": "string" + }, + "tag": { + "$ref": "#/$defs/Tag" + }, + "bgImageAlt": { + "type": "string" + } + }, + "required": [ + "body" + ], + "additionalProperties": false, + "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." + }, + "Tabs": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/TabItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Tabbed container" + }, + "TabItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trigger": { + "type": "string" + }, + "content": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + } + }, + "required": [ + "value", + "trigger", + "content" + ], + "additionalProperties": false, + "description": "value is unique id, trigger is tab label, content is array of components" + }, + "Carousel": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + } + }, + "variant": { + "type": "string", + "enum": [ + "card", + "sunk" + ] + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Horizontal scrollable carousel" + }, + "Stack": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": {} + }, + "direction": { + "type": "string", + "enum": [ + "row", + "column" + ] + }, + "gap": { + "type": "string", + "enum": [ + "none", + "xs", + "s", + "m", + "l", + "xl", + "2xl" + ] + }, + "align": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "stretch", + "baseline" + ] + }, + "justify": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "between", + "around", + "evenly" + ] + }, + "wrap": { + "type": "boolean" + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." + }, + "Slice": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "value": { + "type": "number" + } + }, + "required": [ + "category", + "value" + ], + "additionalProperties": false, + "description": "One slice with label and numeric value" + }, + "Label": { + "type": "object", + "properties": { + "text": { + "type": "string" + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Text label" + }, + "SwitchGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/SwitchItem" + } + }, + "variant": { + "type": "string", + "enum": [ + "clear", + "card", + "sunk" + ] + }, + "value": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false, + "description": "Group of switch toggles" + }, + "SwitchItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "defaultChecked": { + "type": "boolean" + } + }, + "required": [ + "name" + ], + "additionalProperties": false, + "description": "Individual switch toggle" + }, + "Accordion": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/AccordionItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Collapsible sections" + }, + "AccordionItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trigger": { + "type": "string" + }, + "content": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + } + }, + "required": [ + "value", + "trigger", + "content" + ], + "additionalProperties": false, + "description": "value is unique id, trigger is section title" + }, + "Modal": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "open": { + "type": "boolean" + }, + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "title", + "children" + ], + "additionalProperties": false, + "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." + } + } + } +} diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json index b4fb7b6ac2..6c3943c3c8 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json @@ -2960,6 +2960,1303 @@ "mutationStatements": [] } }, + { + "name": "openui-example-1", + "schema": "openui", + "input": "Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]", + "expected": { + "root": { + "type": "element", + "typeName": "Stack", + "props": { + "children": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Top Languages", + "size": "large-heavy" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "title" + }, + { + "type": "element", + "typeName": "Table", + "props": { + "columns": [ + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Language", + "data": [ + "Python", + "JavaScript", + "Java", + "TypeScript", + "Go" + ] + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Users (M)", + "data": [ + 15.7, + 14.2, + 12.1, + 8.5, + 5.2 + ] + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Col", + "props": { + "label": "Year", + "data": [ + 1991, + 1995, + 1995, + 2012, + 2009 + ] + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tbl" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 6, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "openui-example-2", + "schema": "openui", + "input": "Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])", + "expected": { + "root": { + "type": "element", + "typeName": "Stack", + "props": { + "children": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Q4 Revenue", + "size": "large-heavy" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "title" + }, + { + "type": "element", + "typeName": "BarChart", + "props": { + "labels": [ + "Oct", + "Nov", + "Dec" + ], + "series": [ + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Product A", + "values": [ + 120, + 150, + 180 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "s1" + }, + { + "type": "element", + "typeName": "Series", + "props": { + "category": "Product B", + "values": [ + 90, + 110, + 140 + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "s2" + } + ], + "variant": "grouped" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "chart" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 6, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "openui-example-3", + "schema": "openui", + "input": "Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Stack", + "props": { + "children": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Contact Us", + "size": "large-heavy" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "title" + }, + { + "type": "element", + "typeName": "Form", + "props": { + "name": "contact", + "buttons": { + "type": "element", + "typeName": "Buttons", + "props": { + "buttons": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Submit", + "action": { + "k": "Comp", + "name": "Action", + "args": [ + { + "k": "Arr", + "els": [ + { + "k": "Comp", + "name": "ToAssistant", + "args": [ + { + "k": "Str", + "v": "Submit" + } + ] + } + ] + } + ] + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": true + }, + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Cancel", + "action": { + "k": "Comp", + "name": "Action", + "args": [ + { + "k": "Arr", + "els": [ + { + "k": "Comp", + "name": "ToAssistant", + "args": [ + { + "k": "Str", + "v": "Cancel" + } + ] + } + ] + } + ] + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "btns" + }, + "fields": [ + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Name", + "input": { + "type": "element", + "typeName": "Input", + "props": { + "name": "name", + "placeholder": "Your name", + "type": "text", + "rules": { + "required": true, + "minLength": 2 + } + }, + "partial": false, + "hasDynamicProps": false + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "nameField" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Email", + "input": { + "type": "element", + "typeName": "Input", + "props": { + "name": "email", + "placeholder": "you@example.com", + "type": "email", + "rules": { + "required": true, + "email": true + } + }, + "partial": false, + "hasDynamicProps": false + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "emailField" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Country", + "input": { + "type": "element", + "typeName": "Select", + "props": { + "name": "country", + "items": [ + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "us", + "label": "United States" + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "uk", + "label": "United Kingdom" + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "SelectItem", + "props": { + "value": "de", + "label": "Germany" + }, + "partial": false, + "hasDynamicProps": false + } + ], + "placeholder": "Select...", + "rules": { + "required": true + } + }, + "partial": false, + "hasDynamicProps": false + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "countryField" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Message", + "input": { + "type": "element", + "typeName": "TextArea", + "props": { + "name": "message", + "placeholder": "Tell us more...", + "rows": 4, + "rules": { + "required": true, + "minLength": 10 + } + }, + "partial": false, + "hasDynamicProps": false + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "msgField" + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "form" + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 9, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "openui-example-4", + "schema": "openui", + "input": "Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]", + "expected": { + "root": { + "type": "element", + "typeName": "Stack", + "props": { + "children": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "React vs Vue", + "size": "large-heavy" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "title" + }, + { + "type": "element", + "typeName": "Tabs", + "props": { + "items": [ + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "react", + "trigger": "React", + "content": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "React is a library by Meta for building UIs." + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Callout", + "props": { + "variant": "info", + "title": "Note", + "description": "React uses JSX syntax." + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabReact" + }, + { + "type": "element", + "typeName": "TabItem", + "props": { + "value": "vue", + "trigger": "Vue", + "content": [ + { + "type": "element", + "typeName": "TextContent", + "props": { + "text": "Vue is a progressive framework by Evan You." + }, + "partial": false, + "hasDynamicProps": false + }, + { + "type": "element", + "typeName": "Callout", + "props": { + "variant": "success", + "title": "Tip", + "description": "Vue has a gentle learning curve." + }, + "partial": false, + "hasDynamicProps": false + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabVue" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tabs" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 7, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "openui-example-5", + "schema": "openui", + "input": "Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")", + "expected": { + "root": { + "type": "element", + "typeName": "Stack", + "props": { + "children": [ + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "This Month", + "description": "Key account metrics" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpiHeader" + }, + { + "type": "element", + "typeName": "SnippetCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "revenue", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "circle-dollar-sign", + "category": "finance" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Revenue", + "subtitle": "Month to date", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "$48,200", + "subtext": "+8.1%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi1" + }, + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "active-users", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "users", + "category": "people" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Active Users", + "subtitle": "This month", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "1,204", + "subtext": "+3.4%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi2" + }, + { + "type": "element", + "typeName": "SnippetCardItem", + "props": { + "id": "churn", + "lhs": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "user-minus", + "category": "people" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Churn", + "subtitle": "This month", + "bold": false, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3lhs" + }, + "rhs": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "number", + "value": "1.8%", + "subtext": "-0.3%", + "subtextVariant": "metric", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3rhs" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpi3" + } + ], + "layout": "grid", + "responsive": true + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "kpiBlock" + }, + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "Top Products", + "description": "By units sold" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "productsHeader" + }, + { + "type": "element", + "typeName": "CompositeCardBlock", + "props": { + "items": [ + { + "type": "element", + "typeName": "CompositeCardItem", + "props": { + "id": "widget-pro", + "header": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "package", + "category": "shopping" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "p1icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Widget Pro", + "subtitle": "Best seller", + "bold": true, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "p1header" + }, + "body": [ + { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "2,410 units", + "subtext": "Sold this month", + "trend": { + "direction": "up", + "value": 12 + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "p1body" + } + ], + "footer": { + "price": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "$29.00", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false + }, + "button": { + "type": "element", + "typeName": "Button", + "props": { + "label": "View Details", + "action": { + "k": "Comp", + "name": "Action", + "args": [ + { + "k": "Arr", + "els": [ + { + "k": "Comp", + "name": "ToAssistant", + "args": [ + { + "k": "Str", + "v": "Show details for Widget Pro" + } + ] + } + ] + } + ] + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "p1btn" + } + } + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "p1" + }, + { + "type": "element", + "typeName": "CompositeCardItem", + "props": { + "id": "widget-mini", + "header": { + "type": "element", + "typeName": "IconText", + "props": { + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "box", + "category": "shopping" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "p2icon" + }, + "iconVariant": "neutral", + "iconSize": "m", + "title": "Widget Mini", + "subtitle": "New arrival", + "bold": true, + "layout": "horizontal" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "p2header" + }, + "body": [ + { + "type": "element", + "typeName": "MetricIndicatorInline", + "props": { + "value": "980 units", + "subtext": "Sold this month", + "trend": { + "direction": "up", + "value": 4 + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "p2body" + } + ], + "footer": { + "price": { + "type": "element", + "typeName": "BoldText", + "props": { + "variant": "text", + "value": "$14.00", + "subtextVariant": "text", + "size": "sm" + }, + "partial": false, + "hasDynamicProps": false + }, + "button": { + "type": "element", + "typeName": "Button", + "props": { + "label": "View Details", + "action": { + "k": "Comp", + "name": "Action", + "args": [ + { + "k": "Arr", + "els": [ + { + "k": "Comp", + "name": "ToAssistant", + "args": [ + { + "k": "Str", + "v": "Show details for Widget Mini" + } + ] + } + ] + } + ] + }, + "variant": "secondary" + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "p2btn" + } + } + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "p2" + } + ], + "layout": "grid", + "responsive": true + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "productCards" + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 29, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, + { + "name": "openui-example-6", + "schema": "openui", + "input": "Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])", + "expected": { + "root": { + "type": "element", + "typeName": "Stack", + "props": { + "children": [ + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "Team Roster", + "description": "Click a cell to edit" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tableHeader" + }, + { + "type": "element", + "typeName": "EditableTable", + "props": { + "name": "roster", + "columns": [ + { + "type": "text", + "key": "name", + "header": "Name" + }, + { + "type": "select", + "key": "role", + "header": "Role", + "options": [ + { + "value": "eng", + "label": "Engineering" + }, + { + "value": "design", + "label": "Design" + } + ] + }, + { + "type": "date-single", + "key": "start", + "header": "Start Date" + } + ], + "data": [ + { + "id": "1", + "values": [ + "Alex Kim", + "eng", + "2024-01-15" + ] + }, + { + "id": "2", + "values": [ + "Jamie Lee", + "design", + "2024-03-02" + ] + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "editTable" + }, + { + "type": "element", + "typeName": "InlineHeader", + "props": { + "heading": "Preferences", + "description": "Tell us how you like to work" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "formHeader" + }, + { + "type": "element", + "typeName": "Form", + "props": { + "name": "prefs", + "buttons": { + "type": "element", + "typeName": "Buttons", + "props": { + "buttons": [ + { + "type": "element", + "typeName": "Button", + "props": { + "label": "Save", + "action": { + "k": "Comp", + "name": "Action", + "args": [ + { + "k": "Arr", + "els": [ + { + "k": "Comp", + "name": "ToAssistant", + "args": [ + { + "k": "Str", + "v": "Save preferences" + } + ] + } + ] + } + ] + }, + "variant": "primary" + }, + "partial": false, + "hasDynamicProps": true + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "formButtons" + }, + "fields": [ + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Working Style", + "input": { + "type": "element", + "typeName": "OptionCards", + "props": { + "name": "style", + "type": "single", + "items": [ + { + "type": "element", + "typeName": "OptionCard", + "props": { + "value": "focused", + "title": "Deep Focus", + "subtitle": "Long uninterrupted blocks", + "topContent": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "target", + "category": "tools" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "style1icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "style1" + }, + { + "type": "element", + "typeName": "OptionCard", + "props": { + "value": "collab", + "title": "Collaborative", + "subtitle": "Frequent pairing and syncs", + "topContent": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "users", + "category": "people" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "style2icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "style2" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "styleCards" + }, + "hint": "Pick the one that fits best" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fc1" + }, + { + "type": "element", + "typeName": "FormControl", + "props": { + "label": "Tools", + "input": { + "type": "element", + "typeName": "Chips", + "props": { + "name": "tools", + "type": "multiple", + "items": [ + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "figma", + "label": "Figma", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "figma", + "category": "design" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tool1icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tool1" + }, + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "slack", + "label": "Slack", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "message-square", + "category": "communication" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tool2icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tool2" + }, + { + "type": "element", + "typeName": "ChipItem", + "props": { + "value": "notion", + "label": "Notion", + "icon": { + "type": "element", + "typeName": "Icon", + "props": { + "name": "notebook", + "category": "text" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tool3icon" + } + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "tool3" + } + ] + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "toolChips" + }, + "hint": "Select all that apply" + }, + "partial": false, + "hasDynamicProps": false, + "statementId": "fc2" + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "prefsForm" + } + ] + }, + "partial": false, + "hasDynamicProps": true, + "statementId": "root" + }, + "meta": { + "incomplete": false, + "unresolved": [], + "orphaned": [], + "statementCount": 27, + "errors": [] + }, + "stateDeclarations": {}, + "queryStatements": [], + "mutationStatements": [] + } + }, { "name": "basic", "schema": "test", diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/prompts.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/prompts.json index 4ab4862d19..e15109c3b4 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/prompts.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/prompts.json @@ -1132,6 +1132,9543 @@ }, "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Content\nCardHeader(title?: string, subtitle?: string) — Header with optional title and subtitle\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nMarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\") — Renders markdown text with optional container variant\nCallout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding) — Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.\nTextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string) — Text callout with variant, title, and description\nImage(alt: string, src?: string) — Image with alt text and optional URL\nImageBlock(src: string, alt?: string) — Image block with loading state\nImageGallery(images: {src: string, alt?: string, details?: string}[]) — Gallery grid of images with modal preview\nCodeBlock(language: string, codeString: string) — Syntax-highlighted code block\nSeparator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean) — Visual divider between content sections\nInlineHeader(heading: string, description?: string) — Compact section heading with an optional one-line description, for use inside cards.\n- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).\n- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card.\n\n### Tables\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\nEditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[]) — Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field\n- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).\n- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.\n\n### Charts (2D)\nBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number) — Vertical bars; use for comparing values across categories with one or more series\nLineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Lines over categories; use for trends and continuous data over time\nAreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Filled area under lines; use for cumulative totals or volume trends over time\nRadarChart(labels: string[], series: Series[]) — Spider/web chart; use for comparing multiple variables across one or more entities\nHorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string) — Horizontal bars; prefer when category labels are long or for ranked lists\nSeries(category: string, values: number[]) — One data series\n\n### Charts (1D)\nPieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\") — Circular slices; use plucked arrays: PieChart(data.categories, data.values)\nRadialChart(labels: string[], values: number[]) — Radial bars; use plucked arrays: RadialChart(data.categories, data.values)\nSingleStackedBarChart(labels: string[], values: number[]) — Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)\nSlice(category: string, value: number) — One slice with label and numeric value\n\n### Charts (Scatter)\nScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string) — X/Y scatter plot; use for correlations, distributions, and clustering\nScatterSeries(name: string, points: Point[]) — Named dataset\nPoint(x: number, y: number, z?: number) — Data point with numeric coordinates\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nLabel(text: string) — Text label\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nTextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nDatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSlider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding) — Numeric slider input; supports continuous and discrete (stepped) variants\nCheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)\nCheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)\nRadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nRadioItem(label: string, description: string, value: string)\nSwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>) — Group of switch toggles\nSwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean) — Individual switch toggle\nChips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.\nChipItem(value: string, label: string, icon?: Icon, disabled?: boolean) — A single selectable chip inside a Chips group, with a value, label and optional icon.\nOptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.\nOptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean) — A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.\n- Chips: compact single/multiple selection pills. Use ChipItem references for each option.\n- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.\n- Define EACH FormControl as its own reference — do NOT inline all controls in one array.\n- NEVER nest Form inside Form.\n- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).\n- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }\n- The renderer shows error messages automatically — do NOT generate error text in the UI\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nIcon(name: string, category?: string) — A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.\nIconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\") — Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.\n- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.\n\n### Lists & Follow-ups\nListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\") — A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.\nListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression) — Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.\nFollowUpBlock(items: FollowUpItem[]) — List of clickable follow-up suggestions placed at the end of a response\nFollowUpItem(text: string) — Clickable follow-up suggestion — when clicked, sends text as user message\n- Use ListBlock with ListItem references for numbered lists.\n- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.\n- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.\n- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.\n- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })\n\n### Sections\nSectionBlock(sections: SectionItem[], isFoldable?: boolean) — Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section.\nSectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[]) — Section with a label and collapsible content — used inside SectionBlock\n- SectionBlock renders collapsible accordion sections that auto-open as they stream.\n- Each section needs a unique `value` id, a `trigger` label, and a `content` array.\n- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])\n- Set isFoldable=false to render sections as flat headers instead of accordion.\n\n### Layout\nTabs(items: TabItem[]) — Tabbed container\nTabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[]) — value is unique id, trigger is tab label, content is array of components\nAccordion(items: AccordionItem[]) — Collapsible sections\nAccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[]) — value is unique id, trigger is section title\nSteps(items: StepsItem[]) — Step-by-step guide\nStepsItem(title: string, details: string) — title and details text for one step\nCarousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\") — Horizontal scrollable carousel\n- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.\n- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])\n- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.\n- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.\n- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs.\n\n### Data Display\nTagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\") — tags is an array of strings; optional size sm | md | lg\nTag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\") — Styled tag/badge with optional Icon and variant\nEntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}) — Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.\n- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.\n\n### Cards\nSnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.\nSnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText) — One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).\nOverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.\nOverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline) — One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.\nContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.\nContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string) — A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.\nCompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.\nCompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button}) — A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.\nVisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.\nVisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string) — A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).\nText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nBoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nIconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\") — An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.\nImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number) — A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.\nImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean) — A full-width banner image above a bold title and optional subtitle. src must be a real image URL.\nMetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional +/- percentage trend and subtext, all on one line.\nMetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.\n- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.\n- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.\n- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.\n- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.\n- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.\n- VisualCardItem: image-first card with a BoldText body and optional Tag.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n\n## Examples\n\nExample 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }\n\nExample 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")\n\nExample 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)\n\nExample 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }\n\nExample 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")\n\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n\n- When asked about data, generate realistic/plausible data\n- Every response is a single Card(children) — children stack vertically automatically. No layout params are needed on Card.\n- Card is the only layout container. Do NOT use Stack. Use Tabs to switch between sections, Carousel for horizontal scroll.\n- Use FollowUpBlock at the END of a Card to suggest what the user can do or ask next.\n- Use ListBlock when presenting a set of options or steps; give each ListItem an action (5th argument) to make it clickable — without one the item is plain text.\n- Use SectionBlock to group long responses into collapsible sections — good for reports, FAQs, and structured content.\n- Use SectionItem inside SectionBlock: each item needs a unique value id, a trigger (header label), and a content array.\n- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])\n- IMPORTANT: Every slide in a Carousel must use the same component structure in the same order — e.g. all slides: [title, image, description, tags].\n- For forms, define one FormControl reference per field so controls can stream progressively.\n- For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).\n- Never nest Form inside Form.\n- CardHeader is the page-level heading — place it as the first child of Card; InlineHeader is a lighter subsection label for a block inside the response, and is redundant when the following component already has a heading.\n- Never use Callout or TextCallout to justify why you did what you did or for any meta-information.\n- Every image slot (Image, ImageBlock, ImageGallery, VisualCardItem/ContextCardItem bgImageSrc, ImageText, ImageTextLarge, ListItem image) requires a REAL URL from a tool result, the conversation, or the user — NEVER invent, guess, or template a URL.\n- If no image URL is in context, compose without image components — icons, gray ContextCardItems, and charts still make rich layouts.\n- Argument-order trap: Image takes alt FIRST, while ImageBlock, ImageText, and ImageTextLarge take src FIRST — alt text in a src slot ships a broken image.\n- Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items, all with the same structure; use layout \"grid\" for primary side-by-side comparison and \"carousel\" for secondary browsing.\n- The card-block action is BLOCK-LEVEL: one action shared by every card, with the clicked card's details attached automatically — keep continue_conversation context generic (e.g. \"Tell me more about this destination\"), and never use a block-level open_url since it would send every card to the same URL.\n- Card items have NO per-item action: to give each item its own external link, use CompositeCardItem with footer { button: Button(label, { type: \"open_url\", url }) } — never claim a card opens a link it cannot.\n- Text, BoldText, IconText, ImageText, ImageTextLarge and MetricIndicator* are inline building blocks used INSIDE card items — do not place them directly in the root Card.\n- EntityList size \"small\" is reserved for CompositeCardItem body content (no header/footer); use size \"default\" elsewhere.\n- Tag variant must be semantically correct (success=positive, danger=negative, warning=cautionary, info=informational, neutral=label); Tag takes an optional Icon second, so use Tag(text, icon, size, variant) when a variant is needed.\n- TagBlock takes plain strings — keep it to at most 3 tags.\n- ListBlock variant \"number\" is for ordered sequences and rankings, \"image\" for products/profiles with a real image; Steps is for ordered sequential processes only.\n- Use SectionBlock to divide a long response into independent, equally prominent topics; use Tabs when the items are alternative views of the same thing; set isFoldable=false unless a section has 4+ distinct blocks; never make SectionBlock the first Card child.\n- Accordion is for supplementary or FAQ content only — never primary information, 3-5 items max, and always the last component in its section or card.\n- Charts: LineChart/AreaChart variant \"natural\" for smooth trends and \"linear\" for precise point-to-point data; BarChart \"grouped\" for side-by-side comparison and \"stacked\" for part-to-whole; prefer HorizontalBarChart when category labels are long or numerous.\n- For large chart values, scale the data and put the unit in the axis label (e.g. yLabel \"Revenue ($k)\") instead of passing raw thousands or millions.\n- Quantitative asks get a chart (plus KPI cards where useful) in the FIRST response — do not answer numbers with prose or a table alone.\n- Table is column-oriented: each Col holds its own data array of plain strings or numbers (never components), and every column's array must have the same length.\n- Use EditableTable ONLY when the user or app explicitly asks for an editable table; default to Table for read-only data.\n- Every Form MUST have EXACTLY ONE submit Button with variant \"primary\" — that button validates the form; other buttons (secondary/tertiary escape hatches like \"Just Surprise Me\") skip validation, and there is never a reset button.\n- Prefer structured inputs (Select, Chips, OptionCards, DatePicker, Slider) over free-text Input, give every FormControl a clear label (and a hint where it prevents mistakes), and keep each field name unique within the response.\n- Validation rules ({ required: true, email: true, minLength: 8, ... }) are enforced with inline errors — use them for genuinely essential fields, but never require a free-text field where leaving it blank is meaningful.\n- Form inputs work ONLY inside a FormControl within a Form; for tappable suggestion choices OUTSIDE a form, use Buttons of continue_conversation Buttons — never a bare OptionCards or Chips.\n- Only add Buttons for real actions: form submit, open_url with a URL from a tool or the user (never fabricated), or a continue_conversation follow-up — never a button for an app action (open, download, export, edit) you cannot perform.\n- Every Button label must accurately describe what clicking it does; use \"primary\" for the main action and \"secondary\"/\"tertiary\" only for lower-emphasis supporting actions.\n- Icon: always include the category argument — it enables fallback matching when the exact lucide name is unavailable.\n- Pass sources on Card ONLY when the answer relies on real references you actually have, and cite them inline in TextContent as [1], [2] (1-based index into sources)." }, + { + "name": "openui-default", + "spec": { + "root": "Stack", + "components": { + "Card": { + "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)", + "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." + }, + "CardHeader": { + "signature": "CardHeader(title?: string, subtitle?: string)", + "description": "Header with optional title and subtitle" + }, + "TextContent": { + "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "MarkDownRenderer": { + "signature": "MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")", + "description": "Renders markdown text with optional container variant" + }, + "Callout": { + "signature": "Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)", + "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." + }, + "TextCallout": { + "signature": "TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)", + "description": "Text callout with variant, title, and description" + }, + "Image": { + "signature": "Image(alt: string, src?: string)", + "description": "Image with alt text and optional URL" + }, + "ImageBlock": { + "signature": "ImageBlock(src: string, alt?: string)", + "description": "Image block with loading state" + }, + "ImageGallery": { + "signature": "ImageGallery(images: {src: string, alt?: string, details?: string}[])", + "description": "Gallery grid of images with modal preview" + }, + "CodeBlock": { + "signature": "CodeBlock(language: string, codeString: string)", + "description": "Syntax-highlighted code block" + }, + "InlineHeader": { + "signature": "InlineHeader(heading: string, description?: string)", + "description": "Compact section heading with an optional one-line description, for use inside cards." + }, + "Table": { + "signature": "Table(columns: Col[])", + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", + "description": "Column definition — holds label + data array" + }, + "EditableTable": { + "signature": "EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])", + "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" + }, + "BarChart": { + "signature": "BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Vertical bars; use for comparing values across categories with one or more series" + }, + "LineChart": { + "signature": "LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Lines over categories; use for trends and continuous data over time" + }, + "AreaChart": { + "signature": "AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Filled area under lines; use for cumulative totals or volume trends over time" + }, + "RadarChart": { + "signature": "RadarChart(labels: string[], series: Series[])", + "description": "Spider/web chart; use for comparing multiple variables across one or more entities" + }, + "HorizontalBarChart": { + "signature": "HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)", + "description": "Horizontal bars; prefer when category labels are long or for ranked lists" + }, + "Series": { + "signature": "Series(category: string, values: number[])", + "description": "One data series" + }, + "PieChart": { + "signature": "PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")", + "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" + }, + "RadialChart": { + "signature": "RadialChart(labels: string[], values: number[])", + "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" + }, + "SingleStackedBarChart": { + "signature": "SingleStackedBarChart(labels: string[], values: number[])", + "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" + }, + "Slice": { + "signature": "Slice(category: string, value: number)", + "description": "One slice with label and numeric value" + }, + "ScatterChart": { + "signature": "ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)", + "description": "X/Y scatter plot; use for correlations, distributions, and clustering" + }, + "ScatterSeries": { + "signature": "ScatterSeries(name: string, points: Point[])", + "description": "Named dataset" + }, + "Point": { + "signature": "Point(x: number, y: number, z?: number)", + "description": "Data point with numeric coordinates" + }, + "Form": { + "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", + "description": "Form container with fields and explicit action buttons" + }, + "FormControl": { + "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", + "description": "Field with label, input component, and optional hint text" + }, + "Label": { + "signature": "Label(text: string)", + "description": "Text label" + }, + "Input": { + "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "TextArea": { + "signature": "TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Select": { + "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", + "description": "" + }, + "SelectItem": { + "signature": "SelectItem(value: string, label: string)", + "description": "Option for Select" + }, + "DatePicker": { + "signature": "DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Slider": { + "signature": "Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "Numeric slider input; supports continuous and discrete (stepped) variants" + }, + "CheckBoxGroup": { + "signature": "CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)", + "description": "" + }, + "CheckBoxItem": { + "signature": "CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)", + "description": "" + }, + "RadioGroup": { + "signature": "RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "RadioItem": { + "signature": "RadioItem(label: string, description: string, value: string)", + "description": "" + }, + "SwitchGroup": { + "signature": "SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)", + "description": "Group of switch toggles" + }, + "SwitchItem": { + "signature": "SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)", + "description": "Individual switch toggle" + }, + "ChipItem": { + "signature": "ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)", + "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." + }, + "Chips": { + "signature": "Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", + "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." + }, + "OptionCard": { + "signature": "OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)", + "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." + }, + "OptionCards": { + "signature": "OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", + "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." + }, + "Button": { + "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", + "description": "Clickable button" + }, + "Buttons": { + "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "IconButton": { + "signature": "IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")", + "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." + }, + "Stack": { + "signature": "Stack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)", + "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." + }, + "Tabs": { + "signature": "Tabs(items: TabItem[])", + "description": "Tabbed container" + }, + "TabItem": { + "signature": "TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])", + "description": "value is unique id, trigger is tab label, content is array of components" + }, + "Accordion": { + "signature": "Accordion(items: AccordionItem[])", + "description": "Collapsible sections" + }, + "AccordionItem": { + "signature": "AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])", + "description": "value is unique id, trigger is section title" + }, + "Steps": { + "signature": "Steps(items: StepsItem[])", + "description": "Step-by-step guide" + }, + "StepsItem": { + "signature": "StepsItem(title: string, details: string)", + "description": "title and details text for one step" + }, + "Carousel": { + "signature": "Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\")", + "description": "Horizontal scrollable carousel" + }, + "Separator": { + "signature": "Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)", + "description": "Visual divider between content sections" + }, + "TagBlock": { + "signature": "TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")", + "description": "tags is an array of strings; optional size sm | md | lg" + }, + "Tag": { + "signature": "Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")", + "description": "Styled tag/badge with optional Icon and variant" + }, + "Icon": { + "signature": "Icon(name: string, category?: string)", + "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." + }, + "EntityList": { + "signature": "EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})", + "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." + }, + "ListBlock": { + "signature": "ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")", + "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." + }, + "ListItem": { + "signature": "ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)", + "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." + }, + "Text": { + "signature": "Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", + "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "BoldText": { + "signature": "BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", + "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "IconText": { + "signature": "IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")", + "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." + }, + "ImageText": { + "signature": "ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)", + "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." + }, + "ImageTextLarge": { + "signature": "ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)", + "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." + }, + "MetricIndicatorInline": { + "signature": "MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})", + "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." + }, + "MetricIndicatorWithStrikethrough": { + "signature": "MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})", + "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." + }, + "SnippetCardItem": { + "signature": "SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)", + "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." + }, + "SnippetCardBlock": { + "signature": "SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." + }, + "OverviewCardItem": { + "signature": "OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)", + "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." + }, + "OverviewCardBlock": { + "signature": "OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." + }, + "ContextCardItem": { + "signature": "ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)", + "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." + }, + "ContextCardBlock": { + "signature": "ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." + }, + "CompositeCardItem": { + "signature": "CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})", + "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." + }, + "CompositeCardBlock": { + "signature": "CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." + }, + "VisualCardItem": { + "signature": "VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)", + "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." + }, + "VisualCardBlock": { + "signature": "VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." + }, + "Modal": { + "signature": "Modal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\")", + "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." + } + }, + "componentGroups": [ + { + "name": "Layout", + "components": [ + "Stack", + "Tabs", + "TabItem", + "Accordion", + "AccordionItem", + "Steps", + "StepsItem", + "Carousel", + "Separator", + "Modal" + ], + "notes": [ + "- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.", + "- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.", + "- Use nested Stacks when you need explicit rows/sections.", + "- Show/hide sections: $editId != \"\" ? Card([editForm]) : null", + "- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.", + "- Use Tabs for alternative views (chart types, data sections) — no $variable needed", + "- Shared filter across Tabs: same $days binding in Query args works across all TabItems" + ] + }, + { + "name": "Content", + "components": [ + "Card", + "CardHeader", + "TextContent", + "MarkDownRenderer", + "Callout", + "TextCallout", + "Image", + "ImageBlock", + "ImageGallery", + "CodeBlock", + "InlineHeader" + ], + "notes": [ + "- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).", + "- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.", + "- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null", + "- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])" + ] + }, + { + "name": "Tables", + "components": [ + "Table", + "Col", + "EditableTable" + ], + "notes": [ + "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", + "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.", + "- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName", + "- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))", + "- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))", + "- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data", + "- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input", + "- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts", + "- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")" + ] + }, + { + "name": "Charts (2D)", + "components": [ + "BarChart", + "LineChart", + "AreaChart", + "RadarChart", + "HorizontalBarChart", + "Series" + ], + "notes": [ + "- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])", + "- Use Cards to wrap charts with CardHeader for titled sections", + "- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data", + "- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])" + ] + }, + { + "name": "Charts (1D)", + "components": [ + "PieChart", + "RadialChart", + "SingleStackedBarChart", + "Slice" + ], + "notes": [ + "- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:", + "- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`", + "- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`" + ] + }, + { + "name": "Charts (Scatter)", + "components": [ + "ScatterChart", + "ScatterSeries", + "Point" + ] + }, + { + "name": "Forms", + "components": [ + "Form", + "FormControl", + "Label", + "Input", + "TextArea", + "Select", + "SelectItem", + "DatePicker", + "Slider", + "CheckBoxGroup", + "CheckBoxItem", + "RadioGroup", + "RadioItem", + "SwitchGroup", + "SwitchItem", + "Chips", + "ChipItem", + "OptionCards", + "OptionCard" + ], + "notes": [ + "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", + "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", + "- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.", + "- NEVER nest Form inside Form — each Form should be a standalone container.", + "- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.", + "- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}", + "- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric", + "- The renderer shows error messages automatically — do NOT generate error text in the UI", + "- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField", + "- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal." + ] + }, + { + "name": "Buttons", + "components": [ + "Button", + "Buttons", + "IconButton" + ], + "notes": [ + "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.", + "- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))" + ] + }, + { + "name": "Data Display", + "components": [ + "TagBlock", + "Tag", + "Icon", + "EntityList", + "ListBlock", + "ListItem" + ], + "notes": [ + "- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")", + "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.", + "- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional." + ] + }, + { + "name": "Cards", + "components": [ + "SnippetCardBlock", + "SnippetCardItem", + "OverviewCardBlock", + "OverviewCardItem", + "ContextCardBlock", + "ContextCardItem", + "CompositeCardBlock", + "CompositeCardItem", + "VisualCardBlock", + "VisualCardItem", + "Text", + "BoldText", + "IconText", + "ImageText", + "ImageTextLarge", + "MetricIndicatorInline", + "MetricIndicatorWithStrikethrough" + ], + "notes": [ + "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", + "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", + "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", + "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", + "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", + "- VisualCardItem: image-first card with a BoldText body and optional Tag.", + "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card." + ] + } + ], + "schema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "Card": { + "$ref": "#/$defs/Card" + }, + "CardHeader": { + "$ref": "#/$defs/CardHeader" + }, + "TextContent": { + "$ref": "#/$defs/TextContent" + }, + "MarkDownRenderer": { + "$ref": "#/$defs/MarkDownRenderer" + }, + "Callout": { + "$ref": "#/$defs/Callout" + }, + "TextCallout": { + "$ref": "#/$defs/TextCallout" + }, + "Image": { + "$ref": "#/$defs/Image" + }, + "ImageBlock": { + "$ref": "#/$defs/ImageBlock" + }, + "ImageGallery": { + "$ref": "#/$defs/ImageGallery" + }, + "CodeBlock": { + "$ref": "#/$defs/CodeBlock" + }, + "InlineHeader": { + "$ref": "#/$defs/InlineHeader" + }, + "Table": { + "$ref": "#/$defs/Table" + }, + "Col": { + "$ref": "#/$defs/Col" + }, + "EditableTable": { + "$ref": "#/$defs/EditableTable" + }, + "BarChart": { + "$ref": "#/$defs/BarChart" + }, + "LineChart": { + "$ref": "#/$defs/LineChart" + }, + "AreaChart": { + "$ref": "#/$defs/AreaChart" + }, + "RadarChart": { + "$ref": "#/$defs/RadarChart" + }, + "HorizontalBarChart": { + "$ref": "#/$defs/HorizontalBarChart" + }, + "Series": { + "$ref": "#/$defs/Series" + }, + "PieChart": { + "$ref": "#/$defs/PieChart" + }, + "RadialChart": { + "$ref": "#/$defs/RadialChart" + }, + "SingleStackedBarChart": { + "$ref": "#/$defs/SingleStackedBarChart" + }, + "Slice": { + "$ref": "#/$defs/Slice" + }, + "ScatterChart": { + "$ref": "#/$defs/ScatterChart" + }, + "ScatterSeries": { + "$ref": "#/$defs/ScatterSeries" + }, + "Point": { + "$ref": "#/$defs/Point" + }, + "Form": { + "$ref": "#/$defs/Form" + }, + "FormControl": { + "$ref": "#/$defs/FormControl" + }, + "Label": { + "$ref": "#/$defs/Label" + }, + "Input": { + "$ref": "#/$defs/Input" + }, + "TextArea": { + "$ref": "#/$defs/TextArea" + }, + "Select": { + "$ref": "#/$defs/Select" + }, + "SelectItem": { + "$ref": "#/$defs/SelectItem" + }, + "DatePicker": { + "$ref": "#/$defs/DatePicker" + }, + "Slider": { + "$ref": "#/$defs/Slider" + }, + "CheckBoxGroup": { + "$ref": "#/$defs/CheckBoxGroup" + }, + "CheckBoxItem": { + "$ref": "#/$defs/CheckBoxItem" + }, + "RadioGroup": { + "$ref": "#/$defs/RadioGroup" + }, + "RadioItem": { + "$ref": "#/$defs/RadioItem" + }, + "SwitchGroup": { + "$ref": "#/$defs/SwitchGroup" + }, + "SwitchItem": { + "$ref": "#/$defs/SwitchItem" + }, + "ChipItem": { + "$ref": "#/$defs/ChipItem" + }, + "Chips": { + "$ref": "#/$defs/Chips" + }, + "OptionCard": { + "$ref": "#/$defs/OptionCard" + }, + "OptionCards": { + "$ref": "#/$defs/OptionCards" + }, + "Button": { + "$ref": "#/$defs/Button" + }, + "Buttons": { + "$ref": "#/$defs/Buttons" + }, + "IconButton": { + "$ref": "#/$defs/IconButton" + }, + "Stack": { + "$ref": "#/$defs/Stack" + }, + "Tabs": { + "$ref": "#/$defs/Tabs" + }, + "TabItem": { + "$ref": "#/$defs/TabItem" + }, + "Accordion": { + "$ref": "#/$defs/Accordion" + }, + "AccordionItem": { + "$ref": "#/$defs/AccordionItem" + }, + "Steps": { + "$ref": "#/$defs/Steps" + }, + "StepsItem": { + "$ref": "#/$defs/StepsItem" + }, + "Carousel": { + "$ref": "#/$defs/Carousel" + }, + "Separator": { + "$ref": "#/$defs/Separator" + }, + "TagBlock": { + "$ref": "#/$defs/TagBlock" + }, + "Tag": { + "$ref": "#/$defs/Tag" + }, + "Icon": { + "$ref": "#/$defs/Icon" + }, + "EntityList": { + "$ref": "#/$defs/EntityList" + }, + "ListBlock": { + "$ref": "#/$defs/ListBlock" + }, + "ListItem": { + "$ref": "#/$defs/ListItem" + }, + "Text": { + "$ref": "#/$defs/Text" + }, + "BoldText": { + "$ref": "#/$defs/BoldText" + }, + "IconText": { + "$ref": "#/$defs/IconText" + }, + "ImageText": { + "$ref": "#/$defs/ImageText" + }, + "ImageTextLarge": { + "$ref": "#/$defs/ImageTextLarge" + }, + "MetricIndicatorInline": { + "$ref": "#/$defs/MetricIndicatorInline" + }, + "MetricIndicatorWithStrikethrough": { + "$ref": "#/$defs/MetricIndicatorWithStrikethrough" + }, + "SnippetCardItem": { + "$ref": "#/$defs/SnippetCardItem" + }, + "SnippetCardBlock": { + "$ref": "#/$defs/SnippetCardBlock" + }, + "OverviewCardItem": { + "$ref": "#/$defs/OverviewCardItem" + }, + "OverviewCardBlock": { + "$ref": "#/$defs/OverviewCardBlock" + }, + "ContextCardItem": { + "$ref": "#/$defs/ContextCardItem" + }, + "ContextCardBlock": { + "$ref": "#/$defs/ContextCardBlock" + }, + "CompositeCardItem": { + "$ref": "#/$defs/CompositeCardItem" + }, + "CompositeCardBlock": { + "$ref": "#/$defs/CompositeCardBlock" + }, + "VisualCardItem": { + "$ref": "#/$defs/VisualCardItem" + }, + "VisualCardBlock": { + "$ref": "#/$defs/VisualCardBlock" + }, + "Modal": { + "$ref": "#/$defs/Modal" + } + }, + "required": [ + "Card", + "CardHeader", + "TextContent", + "MarkDownRenderer", + "Callout", + "TextCallout", + "Image", + "ImageBlock", + "ImageGallery", + "CodeBlock", + "InlineHeader", + "Table", + "Col", + "EditableTable", + "BarChart", + "LineChart", + "AreaChart", + "RadarChart", + "HorizontalBarChart", + "Series", + "PieChart", + "RadialChart", + "SingleStackedBarChart", + "Slice", + "ScatterChart", + "ScatterSeries", + "Point", + "Form", + "FormControl", + "Label", + "Input", + "TextArea", + "Select", + "SelectItem", + "DatePicker", + "Slider", + "CheckBoxGroup", + "CheckBoxItem", + "RadioGroup", + "RadioItem", + "SwitchGroup", + "SwitchItem", + "ChipItem", + "Chips", + "OptionCard", + "OptionCards", + "Button", + "Buttons", + "IconButton", + "Stack", + "Tabs", + "TabItem", + "Accordion", + "AccordionItem", + "Steps", + "StepsItem", + "Carousel", + "Separator", + "TagBlock", + "Tag", + "Icon", + "EntityList", + "ListBlock", + "ListItem", + "Text", + "BoldText", + "IconText", + "ImageText", + "ImageTextLarge", + "MetricIndicatorInline", + "MetricIndicatorWithStrikethrough", + "SnippetCardItem", + "SnippetCardBlock", + "OverviewCardItem", + "OverviewCardBlock", + "ContextCardItem", + "ContextCardBlock", + "CompositeCardItem", + "CompositeCardBlock", + "VisualCardItem", + "VisualCardBlock", + "Modal" + ], + "additionalProperties": false, + "$defs": { + "Card": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + }, + { + "$ref": "#/$defs/Tabs" + }, + { + "$ref": "#/$defs/Carousel" + }, + { + "$ref": "#/$defs/Stack" + } + ] + } + }, + "variant": { + "type": "string", + "enum": [ + "card", + "sunk", + "clear" + ] + }, + "direction": { + "type": "string", + "enum": [ + "row", + "column" + ] + }, + "gap": { + "type": "string", + "enum": [ + "none", + "xs", + "s", + "m", + "l", + "xl", + "2xl" + ] + }, + "align": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "stretch", + "baseline" + ] + }, + "justify": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "between", + "around", + "evenly" + ] + }, + "wrap": { + "type": "boolean" + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." + }, + "TextContent": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "size": { + "type": "string", + "enum": [ + "small", + "default", + "large", + "small-heavy", + "large-heavy" + ] + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "MarkDownRenderer": { + "type": "object", + "properties": { + "textMarkdown": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": [ + "clear", + "card", + "sunk" + ] + } + }, + "required": [ + "textMarkdown" + ], + "additionalProperties": false, + "description": "Renders markdown text with optional container variant" + }, + "CardHeader": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + } + }, + "additionalProperties": false, + "description": "Header with optional title and subtitle" + }, + "Callout": { + "type": "object", + "properties": { + "variant": { + "type": "string", + "enum": [ + "info", + "warning", + "error", + "success", + "neutral" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "visible": { + "type": "boolean" + } + }, + "required": [ + "variant", + "title", + "description" + ], + "additionalProperties": false, + "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." + }, + "TextCallout": { + "type": "object", + "properties": { + "variant": { + "type": "string", + "enum": [ + "neutral", + "info", + "warning", + "success", + "danger" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false, + "description": "Text callout with variant, title, and description" + }, + "CodeBlock": { + "type": "object", + "properties": { + "language": { + "type": "string" + }, + "codeString": { + "type": "string" + } + }, + "required": [ + "language", + "codeString" + ], + "additionalProperties": false, + "description": "Syntax-highlighted code block" + }, + "Image": { + "type": "object", + "properties": { + "alt": { + "type": "string" + }, + "src": { + "type": "string" + } + }, + "required": [ + "alt" + ], + "additionalProperties": false, + "description": "Image with alt text and optional URL" + }, + "ImageBlock": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + } + }, + "required": [ + "src" + ], + "additionalProperties": false, + "description": "Image block with loading state" + }, + "ImageGallery": { + "type": "object", + "properties": { + "images": { + "type": "array", + "items": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "details": { + "type": "string" + } + }, + "required": [ + "src" + ], + "additionalProperties": false + } + } + }, + "required": [ + "images" + ], + "additionalProperties": false, + "description": "Gallery grid of images with modal preview" + }, + "Separator": { + "type": "object", + "properties": { + "orientation": { + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + }, + "decorative": { + "type": "boolean" + } + }, + "additionalProperties": false, + "description": "Visual divider between content sections" + }, + "HorizontalBarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "grouped", + "stacked" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Horizontal bars; prefer when category labels are long or for ranked lists" + }, + "Series": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "category", + "values" + ], + "additionalProperties": false, + "description": "One data series" + }, + "RadarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Spider/web chart; use for comparing multiple variables across one or more entities" + }, + "PieChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + }, + "variant": { + "type": "string", + "enum": [ + "pie", + "donut" + ] + }, + "appearance": { + "type": "string", + "enum": [ + "circular", + "semiCircular" + ] + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" + }, + "RadialChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" + }, + "SingleStackedBarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" + }, + "ScatterChart": { + "type": "object", + "properties": { + "datasets": { + "type": "array", + "items": { + "$ref": "#/$defs/ScatterSeries" + } + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + } + }, + "required": [ + "datasets" + ], + "additionalProperties": false, + "description": "X/Y scatter plot; use for correlations, distributions, and clustering" + }, + "ScatterSeries": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "points": { + "type": "array", + "items": { + "$ref": "#/$defs/Point" + } + } + }, + "required": [ + "name", + "points" + ], + "additionalProperties": false, + "description": "Named dataset" + }, + "Point": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "z": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ], + "additionalProperties": false, + "description": "Data point with numeric coordinates" + }, + "AreaChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "linear", + "natural", + "step" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Filled area under lines; use for cumulative totals or volume trends over time" + }, + "BarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "grouped", + "stacked" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Vertical bars; use for comparing values across categories with one or more series" + }, + "LineChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "linear", + "natural", + "step" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Lines over categories; use for trends and continuous data over time" + }, + "Table": { + "type": "object", + "properties": { + "columns": { + "type": "array", + "items": { + "$ref": "#/$defs/Col" + } + } + }, + "required": [ + "columns" + ], + "additionalProperties": false, + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "data": {}, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "action" + ] + } + }, + "required": [ + "label", + "data" + ], + "additionalProperties": false, + "description": "Column definition — holds label + data array" + }, + "TagBlock": { + "type": "object", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "tags" + ], + "additionalProperties": false, + "description": "tags is an array of strings; optional size sm | md | lg" + }, + "Form": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "buttons": { + "$ref": "#/$defs/Buttons" + }, + "fields": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/FormControl" + } + } + }, + "required": [ + "name", + "buttons", + "fields" + ], + "additionalProperties": false, + "description": "Form container with fields and explicit action buttons" + }, + "Buttons": { + "type": "object", + "properties": { + "buttons": { + "type": "array", + "items": { + "$ref": "#/$defs/Button" + } + }, + "direction": { + "type": "string", + "enum": [ + "row", + "column" + ] + } + }, + "required": [ + "buttons" + ], + "additionalProperties": false, + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "Button": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "variant": { + "type": "string", + "enum": [ + "primary", + "secondary", + "tertiary" + ] + }, + "type": { + "type": "string", + "enum": [ + "normal", + "destructive" + ] + }, + "size": { + "type": "string", + "enum": [ + "extra-small", + "small", + "medium", + "large" + ] + } + }, + "required": [ + "label" + ], + "additionalProperties": false, + "description": "Clickable button" + }, + "FormControl": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "input": { + "anyOf": [ + { + "$ref": "#/$defs/Input" + }, + { + "$ref": "#/$defs/TextArea" + }, + { + "$ref": "#/$defs/Select" + }, + { + "$ref": "#/$defs/DatePicker" + }, + { + "$ref": "#/$defs/Slider" + }, + { + "$ref": "#/$defs/CheckBoxGroup" + }, + { + "$ref": "#/$defs/RadioGroup" + }, + { + "$ref": "#/$defs/Chips" + }, + { + "$ref": "#/$defs/OptionCards" + } + ] + }, + "hint": { + "type": "string" + } + }, + "required": [ + "label", + "input" + ], + "additionalProperties": false, + "description": "Field with label, input component, and optional hint text" + }, + "Input": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "placeholder": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "text", + "email", + "password", + "number", + "url" + ] + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "TextArea": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "placeholder": { + "type": "string" + }, + "rows": { + "type": "number" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "Select": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/SelectItem" + } + }, + "placeholder": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + }, + "size": { + "type": "string", + "enum": [ + "small", + "medium", + "large" + ] + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "SelectItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false, + "description": "Option for Select" + }, + "DatePicker": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "mode": { + "type": "string", + "enum": [ + "single", + "range" + ] + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": {} + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "Slider": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": [ + "continuous", + "discrete" + ] + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "step": { + "type": "number" + }, + "defaultValue": { + "type": "array", + "items": { + "type": "number" + } + }, + "label": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "name", + "variant", + "min", + "max" + ], + "additionalProperties": false, + "description": "Numeric slider input; supports continuous and discrete (stepped) variants" + }, + "CheckBoxGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/CheckBoxItem" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "CheckBoxItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "defaultChecked": { + "type": "boolean" + } + }, + "required": [ + "label", + "description", + "name" + ], + "additionalProperties": false + }, + "RadioGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/RadioItem" + } + }, + "defaultValue": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "RadioItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "description", + "value" + ], + "additionalProperties": false + }, + "Chips": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "default": "multiple", + "type": "string", + "enum": [ + "single", + "multiple" + ] + }, + "items": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/ChipItem" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "defaultValue": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "name", + "type", + "items" + ], + "additionalProperties": false, + "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." + }, + "ChipItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "disabled": { + "type": "boolean" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false, + "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." + }, + "Icon": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "category": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false, + "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." + }, + "OptionCards": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "default": "single", + "type": "string", + "enum": [ + "single", + "multiple" + ] + }, + "items": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/OptionCard" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "defaultValue": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "name", + "type", + "items" + ], + "additionalProperties": false, + "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." + }, + "OptionCard": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "topContent": { + "anyOf": [ + { + "$ref": "#/$defs/Icon" + }, + { + "$ref": "#/$defs/Image" + } + ] + }, + "disabled": { + "type": "boolean" + } + }, + "required": [ + "value", + "title" + ], + "additionalProperties": false, + "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." + }, + "IconButton": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "variant": { + "type": "string", + "enum": [ + "primary", + "secondary", + "tertiary" + ] + }, + "size": { + "type": "string", + "enum": [ + "extra-small", + "small", + "medium", + "large" + ] + }, + "shape": { + "type": "string", + "enum": [ + "square", + "circle" + ] + } + }, + "required": [ + "name", + "icon" + ], + "additionalProperties": false, + "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." + }, + "Steps": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/StepsItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Step-by-step guide" + }, + "StepsItem": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "details": { + "type": "string" + } + }, + "required": [ + "title", + "details" + ], + "additionalProperties": false, + "description": "title and details text for one step" + }, + "InlineHeader": { + "type": "object", + "properties": { + "heading": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "heading" + ], + "additionalProperties": false, + "description": "Compact section heading with an optional one-line description, for use inside cards." + }, + "EntityList": { + "type": "object", + "properties": { + "rows": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + } + }, + "size": { + "default": "default", + "type": "string", + "enum": [ + "small", + "default" + ] + }, + "header": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + }, + "footer": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + } + }, + "required": [ + "rows", + "size" + ], + "additionalProperties": false, + "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." + }, + "EditableTable": { + "type": "object", + "properties": { + "name": { + "default": "", + "type": "string" + }, + "columns": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "text", + "number", + "date-single", + "select", + "url" + ] + }, + "key": { + "default": "default", + "type": "string" + }, + "header": { + "default": "", + "type": "string" + }, + "width": { + "type": "number" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false + } + } + }, + "required": [ + "type", + "key", + "header" + ], + "additionalProperties": false + } + }, + "data": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + } + }, + "required": [ + "id", + "values" + ], + "additionalProperties": false + } + } + }, + "required": [ + "name", + "columns", + "data" + ], + "additionalProperties": false, + "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" + }, + "SnippetCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/SnippetCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." + }, + "SnippetCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "lhs": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + } + ] + }, + "rhs": { + "anyOf": [ + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/BoldText" + } + ] + } + }, + "required": [ + "lhs" + ], + "additionalProperties": false, + "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." + }, + "IconText": { + "type": "object", + "properties": { + "icon": { + "$ref": "#/$defs/Icon" + }, + "iconVariant": { + "default": "neutral", + "type": "string", + "enum": [ + "neutral", + "info", + "success", + "warning", + "danger", + "inverted", + "filled", + "soft" + ] + }, + "iconSize": { + "default": "m", + "type": "string", + "enum": [ + "xs", + "s", + "m", + "l", + "xl", + "sm", + "md", + "lg" + ] + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + }, + "layout": { + "default": "horizontal", + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + } + }, + "required": [ + "icon", + "iconVariant", + "iconSize", + "title", + "bold", + "layout" + ], + "additionalProperties": false, + "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." + }, + "ImageText": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + }, + "layout": { + "default": "horizontal", + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + }, + "imageSize": { + "type": "number" + } + }, + "required": [ + "src", + "title", + "bold", + "layout" + ], + "additionalProperties": false, + "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." + }, + "Text": { + "type": "object", + "properties": { + "variant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + }, + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "subtextVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number", + "metric" + ] + }, + "size": { + "default": "sm", + "type": "string", + "enum": [ + "xs", + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "variant", + "value", + "subtextVariant", + "size" + ], + "additionalProperties": false, + "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "BoldText": { + "type": "object", + "properties": { + "variant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + }, + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "subtextVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number", + "metric" + ] + }, + "size": { + "default": "sm", + "type": "string", + "enum": [ + "xs", + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "variant", + "value", + "subtextVariant", + "size" + ], + "additionalProperties": false, + "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "OverviewCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/OverviewCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." + }, + "OverviewCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "top": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + }, + { + "$ref": "#/$defs/Text" + } + ] + }, + "bottom": { + "$ref": "#/$defs/MetricIndicatorInline" + } + }, + "required": [ + "top" + ], + "additionalProperties": false, + "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." + }, + "MetricIndicatorInline": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "trend": { + "type": "object", + "properties": { + "direction": { + "type": "string", + "enum": [ + "up", + "down" + ] + }, + "value": { + "type": "number" + } + }, + "required": [ + "direction", + "value" + ], + "additionalProperties": false + } + }, + "required": [ + "value" + ], + "additionalProperties": false, + "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." + }, + "ContextCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/ContextCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." + }, + "ContextCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/Tag" + } + ] + }, + "body": { + "type": "string" + }, + "bgColor": { + "type": "string", + "enum": [ + "gray" + ] + }, + "bgImageSrc": { + "type": "string" + }, + "bgImageAlt": { + "type": "string" + } + }, + "required": [ + "title" + ], + "additionalProperties": false, + "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." + }, + "Tag": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + }, + "variant": { + "type": "string", + "enum": [ + "neutral", + "info", + "success", + "warning", + "danger" + ] + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Styled tag/badge with optional Icon and variant" + }, + "CompositeCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/CompositeCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." + }, + "CompositeCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "header": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + }, + { + "$ref": "#/$defs/ImageTextLarge" + }, + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/Image" + } + ] + }, + "body": { + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/BoldText" + }, + { + "$ref": "#/$defs/MetricIndicatorInline" + }, + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/ListBlock" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/EntityList" + } + ] + } + }, + "footer": { + "type": "object", + "properties": { + "price": { + "anyOf": [ + { + "$ref": "#/$defs/BoldText" + }, + { + "$ref": "#/$defs/MetricIndicatorWithStrikethrough" + } + ] + }, + "button": { + "$ref": "#/$defs/Button" + } + }, + "additionalProperties": false + } + }, + "required": [ + "body" + ], + "additionalProperties": false, + "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." + }, + "ImageTextLarge": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + } + }, + "required": [ + "src", + "title", + "bold" + ], + "additionalProperties": false, + "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." + }, + "ListBlock": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/ListItem" + } + }, + "variant": { + "type": "string", + "enum": [ + "number", + "image" + ] + }, + "size": { + "type": "string", + "enum": [ + "default", + "small" + ] + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." + }, + "ListItem": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "image": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + } + }, + "required": [ + "src", + "alt" + ], + "additionalProperties": false + }, + "actionLabel": { + "type": "string" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "title" + ], + "additionalProperties": false, + "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." + }, + "MetricIndicatorWithStrikethrough": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "previousValue": { + "type": "string" + }, + "trend": { + "type": "object", + "properties": { + "direction": { + "type": "string", + "enum": [ + "up", + "down" + ] + }, + "value": { + "type": "number" + } + }, + "required": [ + "direction", + "value" + ], + "additionalProperties": false + } + }, + "required": [ + "value" + ], + "additionalProperties": false, + "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." + }, + "VisualCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/VisualCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." + }, + "VisualCardItem": { + "type": "object", + "properties": { + "body": { + "$ref": "#/$defs/BoldText" + }, + "id": { + "type": "string" + }, + "bgImageSrc": { + "type": "string" + }, + "tag": { + "$ref": "#/$defs/Tag" + }, + "bgImageAlt": { + "type": "string" + } + }, + "required": [ + "body" + ], + "additionalProperties": false, + "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." + }, + "Tabs": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/TabItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Tabbed container" + }, + "TabItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trigger": { + "type": "string" + }, + "content": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + } + }, + "required": [ + "value", + "trigger", + "content" + ], + "additionalProperties": false, + "description": "value is unique id, trigger is tab label, content is array of components" + }, + "Carousel": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + } + }, + "variant": { + "type": "string", + "enum": [ + "card", + "sunk" + ] + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Horizontal scrollable carousel" + }, + "Stack": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": {} + }, + "direction": { + "type": "string", + "enum": [ + "row", + "column" + ] + }, + "gap": { + "type": "string", + "enum": [ + "none", + "xs", + "s", + "m", + "l", + "xl", + "2xl" + ] + }, + "align": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "stretch", + "baseline" + ] + }, + "justify": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "between", + "around", + "evenly" + ] + }, + "wrap": { + "type": "boolean" + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." + }, + "Slice": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "value": { + "type": "number" + } + }, + "required": [ + "category", + "value" + ], + "additionalProperties": false, + "description": "One slice with label and numeric value" + }, + "Label": { + "type": "object", + "properties": { + "text": { + "type": "string" + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Text label" + }, + "SwitchGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/SwitchItem" + } + }, + "variant": { + "type": "string", + "enum": [ + "clear", + "card", + "sunk" + ] + }, + "value": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false, + "description": "Group of switch toggles" + }, + "SwitchItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "defaultChecked": { + "type": "boolean" + } + }, + "required": [ + "name" + ], + "additionalProperties": false, + "description": "Individual switch toggle" + }, + "Accordion": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/AccordionItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Collapsible sections" + }, + "AccordionItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trigger": { + "type": "string" + }, + "content": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + } + }, + "required": [ + "value", + "trigger", + "content" + ], + "additionalProperties": false, + "description": "value is unique id, trigger is section title" + }, + "Modal": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "open": { + "type": "boolean" + }, + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "title", + "children" + ], + "additionalProperties": false, + "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." + } + } + } + }, + "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Stack(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Layout\nStack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean) — Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\".\nTabs(items: TabItem[]) — Tabbed container\nTabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[]) — value is unique id, trigger is tab label, content is array of components\nAccordion(items: AccordionItem[]) — Collapsible sections\nAccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[]) — value is unique id, trigger is section title\nSteps(items: StepsItem[]) — Step-by-step guide\nStepsItem(title: string, details: string) — title and details text for one step\nCarousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\") — Horizontal scrollable carousel\nSeparator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean) — Visual divider between content sections\nModal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\") — Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children.\n- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.\n- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.\n- Use nested Stacks when you need explicit rows/sections.\n- Show/hide sections: $editId != \"\" ? Card([editForm]) : null\n- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.\n- Use Tabs for alternative views (chart types, data sections) — no $variable needed\n- Shared filter across Tabs: same $days binding in Query args works across all TabItems\n\n### Content\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean) — Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts.\nCardHeader(title?: string, subtitle?: string) — Header with optional title and subtitle\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nMarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\") — Renders markdown text with optional container variant\nCallout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding) — Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.\nTextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string) — Text callout with variant, title, and description\nImage(alt: string, src?: string) — Image with alt text and optional URL\nImageBlock(src: string, alt?: string) — Image block with loading state\nImageGallery(images: {src: string, alt?: string, details?: string}[]) — Gallery grid of images with modal preview\nCodeBlock(language: string, codeString: string) — Syntax-highlighted code block\nInlineHeader(heading: string, description?: string) — Compact section heading with an optional one-line description, for use inside cards.\n- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).\n- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.\n- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null\n- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])\n\n### Tables\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\nEditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[]) — Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field\n- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).\n- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.\n- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName\n- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))\n- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))\n- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data\n- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input\n- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts\n- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")\n\n### Charts (2D)\nBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number) — Vertical bars; use for comparing values across categories with one or more series\nLineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Lines over categories; use for trends and continuous data over time\nAreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Filled area under lines; use for cumulative totals or volume trends over time\nRadarChart(labels: string[], series: Series[]) — Spider/web chart; use for comparing multiple variables across one or more entities\nHorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string) — Horizontal bars; prefer when category labels are long or for ranked lists\nSeries(category: string, values: number[]) — One data series\n- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])\n- Use Cards to wrap charts with CardHeader for titled sections\n- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data\n- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])\n\n### Charts (1D)\nPieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\") — Circular slices; use plucked arrays: PieChart(data.categories, data.values)\nRadialChart(labels: string[], values: number[]) — Radial bars; use plucked arrays: RadialChart(data.categories, data.values)\nSingleStackedBarChart(labels: string[], values: number[]) — Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)\nSlice(category: string, value: number) — One slice with label and numeric value\n- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:\n- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`\n- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`\n\n### Charts (Scatter)\nScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string) — X/Y scatter plot; use for correlations, distributions, and clustering\nScatterSeries(name: string, points: Point[]) — Named dataset\nPoint(x: number, y: number, z?: number) — Data point with numeric coordinates\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nLabel(text: string) — Text label\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nTextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nDatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSlider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding) — Numeric slider input; supports continuous and discrete (stepped) variants\nCheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)\nCheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)\nRadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nRadioItem(label: string, description: string, value: string)\nSwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>) — Group of switch toggles\nSwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean) — Individual switch toggle\nChips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.\nChipItem(value: string, label: string, icon?: Icon, disabled?: boolean) — A single selectable chip inside a Chips group, with a value, label and optional icon.\nOptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.\nOptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean) — A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.\n- Chips: compact single/multiple selection pills. Use ChipItem references for each option.\n- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.\n- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.\n- NEVER nest Form inside Form — each Form should be a standalone container.\n- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.\n- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}\n- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric\n- The renderer shows error messages automatically — do NOT generate error text in the UI\n- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField\n- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal.\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nIconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\") — Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.\n- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.\n- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))\n\n### Data Display\nTagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\") — tags is an array of strings; optional size sm | md | lg\nTag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\") — Styled tag/badge with optional Icon and variant\nIcon(name: string, category?: string) — A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.\nEntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}) — Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.\nListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\") — A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.\nListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression) — Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.\n- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")\n- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.\n- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional.\n\n### Cards\nSnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.\nSnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText) — One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).\nOverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.\nOverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline) — One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.\nContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.\nContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string) — A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.\nCompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.\nCompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button}) — A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.\nVisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.\nVisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string) — A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).\nText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nBoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nIconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\") — An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.\nImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number) — A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.\nImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean) — A full-width banner image above a bold title and optional subtitle. src must be a real image URL.\nMetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional +/- percentage trend and subtext, all on one line.\nMetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.\n- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.\n- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.\n- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.\n- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.\n- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.\n- VisualCardItem: image-first card with a BoldText body and optional Tag.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Stack(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Stack(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Stack(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root." + }, + { + "name": "openui-options", + "spec": { + "root": "Stack", + "components": { + "Card": { + "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)", + "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." + }, + "CardHeader": { + "signature": "CardHeader(title?: string, subtitle?: string)", + "description": "Header with optional title and subtitle" + }, + "TextContent": { + "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "MarkDownRenderer": { + "signature": "MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")", + "description": "Renders markdown text with optional container variant" + }, + "Callout": { + "signature": "Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)", + "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." + }, + "TextCallout": { + "signature": "TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)", + "description": "Text callout with variant, title, and description" + }, + "Image": { + "signature": "Image(alt: string, src?: string)", + "description": "Image with alt text and optional URL" + }, + "ImageBlock": { + "signature": "ImageBlock(src: string, alt?: string)", + "description": "Image block with loading state" + }, + "ImageGallery": { + "signature": "ImageGallery(images: {src: string, alt?: string, details?: string}[])", + "description": "Gallery grid of images with modal preview" + }, + "CodeBlock": { + "signature": "CodeBlock(language: string, codeString: string)", + "description": "Syntax-highlighted code block" + }, + "InlineHeader": { + "signature": "InlineHeader(heading: string, description?: string)", + "description": "Compact section heading with an optional one-line description, for use inside cards." + }, + "Table": { + "signature": "Table(columns: Col[])", + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", + "description": "Column definition — holds label + data array" + }, + "EditableTable": { + "signature": "EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])", + "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" + }, + "BarChart": { + "signature": "BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Vertical bars; use for comparing values across categories with one or more series" + }, + "LineChart": { + "signature": "LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Lines over categories; use for trends and continuous data over time" + }, + "AreaChart": { + "signature": "AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", + "description": "Filled area under lines; use for cumulative totals or volume trends over time" + }, + "RadarChart": { + "signature": "RadarChart(labels: string[], series: Series[])", + "description": "Spider/web chart; use for comparing multiple variables across one or more entities" + }, + "HorizontalBarChart": { + "signature": "HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)", + "description": "Horizontal bars; prefer when category labels are long or for ranked lists" + }, + "Series": { + "signature": "Series(category: string, values: number[])", + "description": "One data series" + }, + "PieChart": { + "signature": "PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")", + "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" + }, + "RadialChart": { + "signature": "RadialChart(labels: string[], values: number[])", + "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" + }, + "SingleStackedBarChart": { + "signature": "SingleStackedBarChart(labels: string[], values: number[])", + "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" + }, + "Slice": { + "signature": "Slice(category: string, value: number)", + "description": "One slice with label and numeric value" + }, + "ScatterChart": { + "signature": "ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)", + "description": "X/Y scatter plot; use for correlations, distributions, and clustering" + }, + "ScatterSeries": { + "signature": "ScatterSeries(name: string, points: Point[])", + "description": "Named dataset" + }, + "Point": { + "signature": "Point(x: number, y: number, z?: number)", + "description": "Data point with numeric coordinates" + }, + "Form": { + "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", + "description": "Form container with fields and explicit action buttons" + }, + "FormControl": { + "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", + "description": "Field with label, input component, and optional hint text" + }, + "Label": { + "signature": "Label(text: string)", + "description": "Text label" + }, + "Input": { + "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "TextArea": { + "signature": "TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Select": { + "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", + "description": "" + }, + "SelectItem": { + "signature": "SelectItem(value: string, label: string)", + "description": "Option for Select" + }, + "DatePicker": { + "signature": "DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "Slider": { + "signature": "Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "Numeric slider input; supports continuous and discrete (stepped) variants" + }, + "CheckBoxGroup": { + "signature": "CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)", + "description": "" + }, + "CheckBoxItem": { + "signature": "CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)", + "description": "" + }, + "RadioGroup": { + "signature": "RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", + "description": "" + }, + "RadioItem": { + "signature": "RadioItem(label: string, description: string, value: string)", + "description": "" + }, + "SwitchGroup": { + "signature": "SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)", + "description": "Group of switch toggles" + }, + "SwitchItem": { + "signature": "SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)", + "description": "Individual switch toggle" + }, + "ChipItem": { + "signature": "ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)", + "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." + }, + "Chips": { + "signature": "Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", + "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." + }, + "OptionCard": { + "signature": "OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)", + "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." + }, + "OptionCards": { + "signature": "OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", + "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." + }, + "Button": { + "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", + "description": "Clickable button" + }, + "Buttons": { + "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "IconButton": { + "signature": "IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")", + "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." + }, + "Stack": { + "signature": "Stack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)", + "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." + }, + "Tabs": { + "signature": "Tabs(items: TabItem[])", + "description": "Tabbed container" + }, + "TabItem": { + "signature": "TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])", + "description": "value is unique id, trigger is tab label, content is array of components" + }, + "Accordion": { + "signature": "Accordion(items: AccordionItem[])", + "description": "Collapsible sections" + }, + "AccordionItem": { + "signature": "AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])", + "description": "value is unique id, trigger is section title" + }, + "Steps": { + "signature": "Steps(items: StepsItem[])", + "description": "Step-by-step guide" + }, + "StepsItem": { + "signature": "StepsItem(title: string, details: string)", + "description": "title and details text for one step" + }, + "Carousel": { + "signature": "Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\")", + "description": "Horizontal scrollable carousel" + }, + "Separator": { + "signature": "Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)", + "description": "Visual divider between content sections" + }, + "TagBlock": { + "signature": "TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")", + "description": "tags is an array of strings; optional size sm | md | lg" + }, + "Tag": { + "signature": "Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")", + "description": "Styled tag/badge with optional Icon and variant" + }, + "Icon": { + "signature": "Icon(name: string, category?: string)", + "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." + }, + "EntityList": { + "signature": "EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})", + "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." + }, + "ListBlock": { + "signature": "ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")", + "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." + }, + "ListItem": { + "signature": "ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)", + "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." + }, + "Text": { + "signature": "Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", + "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "BoldText": { + "signature": "BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", + "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "IconText": { + "signature": "IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")", + "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." + }, + "ImageText": { + "signature": "ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)", + "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." + }, + "ImageTextLarge": { + "signature": "ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)", + "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." + }, + "MetricIndicatorInline": { + "signature": "MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})", + "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." + }, + "MetricIndicatorWithStrikethrough": { + "signature": "MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})", + "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." + }, + "SnippetCardItem": { + "signature": "SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)", + "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." + }, + "SnippetCardBlock": { + "signature": "SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." + }, + "OverviewCardItem": { + "signature": "OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)", + "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." + }, + "OverviewCardBlock": { + "signature": "OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." + }, + "ContextCardItem": { + "signature": "ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)", + "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." + }, + "ContextCardBlock": { + "signature": "ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." + }, + "CompositeCardItem": { + "signature": "CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})", + "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." + }, + "CompositeCardBlock": { + "signature": "CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." + }, + "VisualCardItem": { + "signature": "VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)", + "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." + }, + "VisualCardBlock": { + "signature": "VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", + "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." + }, + "Modal": { + "signature": "Modal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\")", + "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." + } + }, + "componentGroups": [ + { + "name": "Layout", + "components": [ + "Stack", + "Tabs", + "TabItem", + "Accordion", + "AccordionItem", + "Steps", + "StepsItem", + "Carousel", + "Separator", + "Modal" + ], + "notes": [ + "- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.", + "- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.", + "- Use nested Stacks when you need explicit rows/sections.", + "- Show/hide sections: $editId != \"\" ? Card([editForm]) : null", + "- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.", + "- Use Tabs for alternative views (chart types, data sections) — no $variable needed", + "- Shared filter across Tabs: same $days binding in Query args works across all TabItems" + ] + }, + { + "name": "Content", + "components": [ + "Card", + "CardHeader", + "TextContent", + "MarkDownRenderer", + "Callout", + "TextCallout", + "Image", + "ImageBlock", + "ImageGallery", + "CodeBlock", + "InlineHeader" + ], + "notes": [ + "- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).", + "- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.", + "- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null", + "- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])" + ] + }, + { + "name": "Tables", + "components": [ + "Table", + "Col", + "EditableTable" + ], + "notes": [ + "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", + "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.", + "- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName", + "- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))", + "- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))", + "- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data", + "- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input", + "- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts", + "- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")" + ] + }, + { + "name": "Charts (2D)", + "components": [ + "BarChart", + "LineChart", + "AreaChart", + "RadarChart", + "HorizontalBarChart", + "Series" + ], + "notes": [ + "- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])", + "- Use Cards to wrap charts with CardHeader for titled sections", + "- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data", + "- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])" + ] + }, + { + "name": "Charts (1D)", + "components": [ + "PieChart", + "RadialChart", + "SingleStackedBarChart", + "Slice" + ], + "notes": [ + "- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:", + "- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`", + "- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`" + ] + }, + { + "name": "Charts (Scatter)", + "components": [ + "ScatterChart", + "ScatterSeries", + "Point" + ] + }, + { + "name": "Forms", + "components": [ + "Form", + "FormControl", + "Label", + "Input", + "TextArea", + "Select", + "SelectItem", + "DatePicker", + "Slider", + "CheckBoxGroup", + "CheckBoxItem", + "RadioGroup", + "RadioItem", + "SwitchGroup", + "SwitchItem", + "Chips", + "ChipItem", + "OptionCards", + "OptionCard" + ], + "notes": [ + "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", + "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", + "- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.", + "- NEVER nest Form inside Form — each Form should be a standalone container.", + "- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.", + "- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}", + "- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric", + "- The renderer shows error messages automatically — do NOT generate error text in the UI", + "- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField", + "- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal." + ] + }, + { + "name": "Buttons", + "components": [ + "Button", + "Buttons", + "IconButton" + ], + "notes": [ + "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.", + "- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))" + ] + }, + { + "name": "Data Display", + "components": [ + "TagBlock", + "Tag", + "Icon", + "EntityList", + "ListBlock", + "ListItem" + ], + "notes": [ + "- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")", + "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.", + "- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional." + ] + }, + { + "name": "Cards", + "components": [ + "SnippetCardBlock", + "SnippetCardItem", + "OverviewCardBlock", + "OverviewCardItem", + "ContextCardBlock", + "ContextCardItem", + "CompositeCardBlock", + "CompositeCardItem", + "VisualCardBlock", + "VisualCardItem", + "Text", + "BoldText", + "IconText", + "ImageText", + "ImageTextLarge", + "MetricIndicatorInline", + "MetricIndicatorWithStrikethrough" + ], + "notes": [ + "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", + "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", + "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", + "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", + "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", + "- VisualCardItem: image-first card with a BoldText body and optional Tag.", + "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card." + ] + } + ], + "schema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "Card": { + "$ref": "#/$defs/Card" + }, + "CardHeader": { + "$ref": "#/$defs/CardHeader" + }, + "TextContent": { + "$ref": "#/$defs/TextContent" + }, + "MarkDownRenderer": { + "$ref": "#/$defs/MarkDownRenderer" + }, + "Callout": { + "$ref": "#/$defs/Callout" + }, + "TextCallout": { + "$ref": "#/$defs/TextCallout" + }, + "Image": { + "$ref": "#/$defs/Image" + }, + "ImageBlock": { + "$ref": "#/$defs/ImageBlock" + }, + "ImageGallery": { + "$ref": "#/$defs/ImageGallery" + }, + "CodeBlock": { + "$ref": "#/$defs/CodeBlock" + }, + "InlineHeader": { + "$ref": "#/$defs/InlineHeader" + }, + "Table": { + "$ref": "#/$defs/Table" + }, + "Col": { + "$ref": "#/$defs/Col" + }, + "EditableTable": { + "$ref": "#/$defs/EditableTable" + }, + "BarChart": { + "$ref": "#/$defs/BarChart" + }, + "LineChart": { + "$ref": "#/$defs/LineChart" + }, + "AreaChart": { + "$ref": "#/$defs/AreaChart" + }, + "RadarChart": { + "$ref": "#/$defs/RadarChart" + }, + "HorizontalBarChart": { + "$ref": "#/$defs/HorizontalBarChart" + }, + "Series": { + "$ref": "#/$defs/Series" + }, + "PieChart": { + "$ref": "#/$defs/PieChart" + }, + "RadialChart": { + "$ref": "#/$defs/RadialChart" + }, + "SingleStackedBarChart": { + "$ref": "#/$defs/SingleStackedBarChart" + }, + "Slice": { + "$ref": "#/$defs/Slice" + }, + "ScatterChart": { + "$ref": "#/$defs/ScatterChart" + }, + "ScatterSeries": { + "$ref": "#/$defs/ScatterSeries" + }, + "Point": { + "$ref": "#/$defs/Point" + }, + "Form": { + "$ref": "#/$defs/Form" + }, + "FormControl": { + "$ref": "#/$defs/FormControl" + }, + "Label": { + "$ref": "#/$defs/Label" + }, + "Input": { + "$ref": "#/$defs/Input" + }, + "TextArea": { + "$ref": "#/$defs/TextArea" + }, + "Select": { + "$ref": "#/$defs/Select" + }, + "SelectItem": { + "$ref": "#/$defs/SelectItem" + }, + "DatePicker": { + "$ref": "#/$defs/DatePicker" + }, + "Slider": { + "$ref": "#/$defs/Slider" + }, + "CheckBoxGroup": { + "$ref": "#/$defs/CheckBoxGroup" + }, + "CheckBoxItem": { + "$ref": "#/$defs/CheckBoxItem" + }, + "RadioGroup": { + "$ref": "#/$defs/RadioGroup" + }, + "RadioItem": { + "$ref": "#/$defs/RadioItem" + }, + "SwitchGroup": { + "$ref": "#/$defs/SwitchGroup" + }, + "SwitchItem": { + "$ref": "#/$defs/SwitchItem" + }, + "ChipItem": { + "$ref": "#/$defs/ChipItem" + }, + "Chips": { + "$ref": "#/$defs/Chips" + }, + "OptionCard": { + "$ref": "#/$defs/OptionCard" + }, + "OptionCards": { + "$ref": "#/$defs/OptionCards" + }, + "Button": { + "$ref": "#/$defs/Button" + }, + "Buttons": { + "$ref": "#/$defs/Buttons" + }, + "IconButton": { + "$ref": "#/$defs/IconButton" + }, + "Stack": { + "$ref": "#/$defs/Stack" + }, + "Tabs": { + "$ref": "#/$defs/Tabs" + }, + "TabItem": { + "$ref": "#/$defs/TabItem" + }, + "Accordion": { + "$ref": "#/$defs/Accordion" + }, + "AccordionItem": { + "$ref": "#/$defs/AccordionItem" + }, + "Steps": { + "$ref": "#/$defs/Steps" + }, + "StepsItem": { + "$ref": "#/$defs/StepsItem" + }, + "Carousel": { + "$ref": "#/$defs/Carousel" + }, + "Separator": { + "$ref": "#/$defs/Separator" + }, + "TagBlock": { + "$ref": "#/$defs/TagBlock" + }, + "Tag": { + "$ref": "#/$defs/Tag" + }, + "Icon": { + "$ref": "#/$defs/Icon" + }, + "EntityList": { + "$ref": "#/$defs/EntityList" + }, + "ListBlock": { + "$ref": "#/$defs/ListBlock" + }, + "ListItem": { + "$ref": "#/$defs/ListItem" + }, + "Text": { + "$ref": "#/$defs/Text" + }, + "BoldText": { + "$ref": "#/$defs/BoldText" + }, + "IconText": { + "$ref": "#/$defs/IconText" + }, + "ImageText": { + "$ref": "#/$defs/ImageText" + }, + "ImageTextLarge": { + "$ref": "#/$defs/ImageTextLarge" + }, + "MetricIndicatorInline": { + "$ref": "#/$defs/MetricIndicatorInline" + }, + "MetricIndicatorWithStrikethrough": { + "$ref": "#/$defs/MetricIndicatorWithStrikethrough" + }, + "SnippetCardItem": { + "$ref": "#/$defs/SnippetCardItem" + }, + "SnippetCardBlock": { + "$ref": "#/$defs/SnippetCardBlock" + }, + "OverviewCardItem": { + "$ref": "#/$defs/OverviewCardItem" + }, + "OverviewCardBlock": { + "$ref": "#/$defs/OverviewCardBlock" + }, + "ContextCardItem": { + "$ref": "#/$defs/ContextCardItem" + }, + "ContextCardBlock": { + "$ref": "#/$defs/ContextCardBlock" + }, + "CompositeCardItem": { + "$ref": "#/$defs/CompositeCardItem" + }, + "CompositeCardBlock": { + "$ref": "#/$defs/CompositeCardBlock" + }, + "VisualCardItem": { + "$ref": "#/$defs/VisualCardItem" + }, + "VisualCardBlock": { + "$ref": "#/$defs/VisualCardBlock" + }, + "Modal": { + "$ref": "#/$defs/Modal" + } + }, + "required": [ + "Card", + "CardHeader", + "TextContent", + "MarkDownRenderer", + "Callout", + "TextCallout", + "Image", + "ImageBlock", + "ImageGallery", + "CodeBlock", + "InlineHeader", + "Table", + "Col", + "EditableTable", + "BarChart", + "LineChart", + "AreaChart", + "RadarChart", + "HorizontalBarChart", + "Series", + "PieChart", + "RadialChart", + "SingleStackedBarChart", + "Slice", + "ScatterChart", + "ScatterSeries", + "Point", + "Form", + "FormControl", + "Label", + "Input", + "TextArea", + "Select", + "SelectItem", + "DatePicker", + "Slider", + "CheckBoxGroup", + "CheckBoxItem", + "RadioGroup", + "RadioItem", + "SwitchGroup", + "SwitchItem", + "ChipItem", + "Chips", + "OptionCard", + "OptionCards", + "Button", + "Buttons", + "IconButton", + "Stack", + "Tabs", + "TabItem", + "Accordion", + "AccordionItem", + "Steps", + "StepsItem", + "Carousel", + "Separator", + "TagBlock", + "Tag", + "Icon", + "EntityList", + "ListBlock", + "ListItem", + "Text", + "BoldText", + "IconText", + "ImageText", + "ImageTextLarge", + "MetricIndicatorInline", + "MetricIndicatorWithStrikethrough", + "SnippetCardItem", + "SnippetCardBlock", + "OverviewCardItem", + "OverviewCardBlock", + "ContextCardItem", + "ContextCardBlock", + "CompositeCardItem", + "CompositeCardBlock", + "VisualCardItem", + "VisualCardBlock", + "Modal" + ], + "additionalProperties": false, + "$defs": { + "Card": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + }, + { + "$ref": "#/$defs/Tabs" + }, + { + "$ref": "#/$defs/Carousel" + }, + { + "$ref": "#/$defs/Stack" + } + ] + } + }, + "variant": { + "type": "string", + "enum": [ + "card", + "sunk", + "clear" + ] + }, + "direction": { + "type": "string", + "enum": [ + "row", + "column" + ] + }, + "gap": { + "type": "string", + "enum": [ + "none", + "xs", + "s", + "m", + "l", + "xl", + "2xl" + ] + }, + "align": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "stretch", + "baseline" + ] + }, + "justify": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "between", + "around", + "evenly" + ] + }, + "wrap": { + "type": "boolean" + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." + }, + "TextContent": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "size": { + "type": "string", + "enum": [ + "small", + "default", + "large", + "small-heavy", + "large-heavy" + ] + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "MarkDownRenderer": { + "type": "object", + "properties": { + "textMarkdown": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": [ + "clear", + "card", + "sunk" + ] + } + }, + "required": [ + "textMarkdown" + ], + "additionalProperties": false, + "description": "Renders markdown text with optional container variant" + }, + "CardHeader": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + } + }, + "additionalProperties": false, + "description": "Header with optional title and subtitle" + }, + "Callout": { + "type": "object", + "properties": { + "variant": { + "type": "string", + "enum": [ + "info", + "warning", + "error", + "success", + "neutral" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "visible": { + "type": "boolean" + } + }, + "required": [ + "variant", + "title", + "description" + ], + "additionalProperties": false, + "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." + }, + "TextCallout": { + "type": "object", + "properties": { + "variant": { + "type": "string", + "enum": [ + "neutral", + "info", + "warning", + "success", + "danger" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false, + "description": "Text callout with variant, title, and description" + }, + "CodeBlock": { + "type": "object", + "properties": { + "language": { + "type": "string" + }, + "codeString": { + "type": "string" + } + }, + "required": [ + "language", + "codeString" + ], + "additionalProperties": false, + "description": "Syntax-highlighted code block" + }, + "Image": { + "type": "object", + "properties": { + "alt": { + "type": "string" + }, + "src": { + "type": "string" + } + }, + "required": [ + "alt" + ], + "additionalProperties": false, + "description": "Image with alt text and optional URL" + }, + "ImageBlock": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + } + }, + "required": [ + "src" + ], + "additionalProperties": false, + "description": "Image block with loading state" + }, + "ImageGallery": { + "type": "object", + "properties": { + "images": { + "type": "array", + "items": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "details": { + "type": "string" + } + }, + "required": [ + "src" + ], + "additionalProperties": false + } + } + }, + "required": [ + "images" + ], + "additionalProperties": false, + "description": "Gallery grid of images with modal preview" + }, + "Separator": { + "type": "object", + "properties": { + "orientation": { + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + }, + "decorative": { + "type": "boolean" + } + }, + "additionalProperties": false, + "description": "Visual divider between content sections" + }, + "HorizontalBarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "grouped", + "stacked" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Horizontal bars; prefer when category labels are long or for ranked lists" + }, + "Series": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "category", + "values" + ], + "additionalProperties": false, + "description": "One data series" + }, + "RadarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Spider/web chart; use for comparing multiple variables across one or more entities" + }, + "PieChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + }, + "variant": { + "type": "string", + "enum": [ + "pie", + "donut" + ] + }, + "appearance": { + "type": "string", + "enum": [ + "circular", + "semiCircular" + ] + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" + }, + "RadialChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" + }, + "SingleStackedBarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" + }, + "ScatterChart": { + "type": "object", + "properties": { + "datasets": { + "type": "array", + "items": { + "$ref": "#/$defs/ScatterSeries" + } + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + } + }, + "required": [ + "datasets" + ], + "additionalProperties": false, + "description": "X/Y scatter plot; use for correlations, distributions, and clustering" + }, + "ScatterSeries": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "points": { + "type": "array", + "items": { + "$ref": "#/$defs/Point" + } + } + }, + "required": [ + "name", + "points" + ], + "additionalProperties": false, + "description": "Named dataset" + }, + "Point": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "z": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ], + "additionalProperties": false, + "description": "Data point with numeric coordinates" + }, + "AreaChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "linear", + "natural", + "step" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Filled area under lines; use for cumulative totals or volume trends over time" + }, + "BarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "grouped", + "stacked" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Vertical bars; use for comparing values across categories with one or more series" + }, + "LineChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "linear", + "natural", + "step" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Lines over categories; use for trends and continuous data over time" + }, + "Table": { + "type": "object", + "properties": { + "columns": { + "type": "array", + "items": { + "$ref": "#/$defs/Col" + } + } + }, + "required": [ + "columns" + ], + "additionalProperties": false, + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "data": {}, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "action" + ] + } + }, + "required": [ + "label", + "data" + ], + "additionalProperties": false, + "description": "Column definition — holds label + data array" + }, + "TagBlock": { + "type": "object", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "tags" + ], + "additionalProperties": false, + "description": "tags is an array of strings; optional size sm | md | lg" + }, + "Form": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "buttons": { + "$ref": "#/$defs/Buttons" + }, + "fields": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/FormControl" + } + } + }, + "required": [ + "name", + "buttons", + "fields" + ], + "additionalProperties": false, + "description": "Form container with fields and explicit action buttons" + }, + "Buttons": { + "type": "object", + "properties": { + "buttons": { + "type": "array", + "items": { + "$ref": "#/$defs/Button" + } + }, + "direction": { + "type": "string", + "enum": [ + "row", + "column" + ] + } + }, + "required": [ + "buttons" + ], + "additionalProperties": false, + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "Button": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "variant": { + "type": "string", + "enum": [ + "primary", + "secondary", + "tertiary" + ] + }, + "type": { + "type": "string", + "enum": [ + "normal", + "destructive" + ] + }, + "size": { + "type": "string", + "enum": [ + "extra-small", + "small", + "medium", + "large" + ] + } + }, + "required": [ + "label" + ], + "additionalProperties": false, + "description": "Clickable button" + }, + "FormControl": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "input": { + "anyOf": [ + { + "$ref": "#/$defs/Input" + }, + { + "$ref": "#/$defs/TextArea" + }, + { + "$ref": "#/$defs/Select" + }, + { + "$ref": "#/$defs/DatePicker" + }, + { + "$ref": "#/$defs/Slider" + }, + { + "$ref": "#/$defs/CheckBoxGroup" + }, + { + "$ref": "#/$defs/RadioGroup" + }, + { + "$ref": "#/$defs/Chips" + }, + { + "$ref": "#/$defs/OptionCards" + } + ] + }, + "hint": { + "type": "string" + } + }, + "required": [ + "label", + "input" + ], + "additionalProperties": false, + "description": "Field with label, input component, and optional hint text" + }, + "Input": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "placeholder": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "text", + "email", + "password", + "number", + "url" + ] + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "TextArea": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "placeholder": { + "type": "string" + }, + "rows": { + "type": "number" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "Select": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/SelectItem" + } + }, + "placeholder": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + }, + "size": { + "type": "string", + "enum": [ + "small", + "medium", + "large" + ] + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "SelectItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false, + "description": "Option for Select" + }, + "DatePicker": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "mode": { + "type": "string", + "enum": [ + "single", + "range" + ] + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": {} + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "Slider": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": [ + "continuous", + "discrete" + ] + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "step": { + "type": "number" + }, + "defaultValue": { + "type": "array", + "items": { + "type": "number" + } + }, + "label": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "name", + "variant", + "min", + "max" + ], + "additionalProperties": false, + "description": "Numeric slider input; supports continuous and discrete (stepped) variants" + }, + "CheckBoxGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/CheckBoxItem" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "CheckBoxItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "defaultChecked": { + "type": "boolean" + } + }, + "required": [ + "label", + "description", + "name" + ], + "additionalProperties": false + }, + "RadioGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/RadioItem" + } + }, + "defaultValue": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "RadioItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "description", + "value" + ], + "additionalProperties": false + }, + "Chips": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "default": "multiple", + "type": "string", + "enum": [ + "single", + "multiple" + ] + }, + "items": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/ChipItem" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "defaultValue": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "name", + "type", + "items" + ], + "additionalProperties": false, + "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." + }, + "ChipItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "disabled": { + "type": "boolean" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false, + "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." + }, + "Icon": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "category": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false, + "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." + }, + "OptionCards": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "default": "single", + "type": "string", + "enum": [ + "single", + "multiple" + ] + }, + "items": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/OptionCard" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "defaultValue": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "name", + "type", + "items" + ], + "additionalProperties": false, + "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." + }, + "OptionCard": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "topContent": { + "anyOf": [ + { + "$ref": "#/$defs/Icon" + }, + { + "$ref": "#/$defs/Image" + } + ] + }, + "disabled": { + "type": "boolean" + } + }, + "required": [ + "value", + "title" + ], + "additionalProperties": false, + "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." + }, + "IconButton": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "variant": { + "type": "string", + "enum": [ + "primary", + "secondary", + "tertiary" + ] + }, + "size": { + "type": "string", + "enum": [ + "extra-small", + "small", + "medium", + "large" + ] + }, + "shape": { + "type": "string", + "enum": [ + "square", + "circle" + ] + } + }, + "required": [ + "name", + "icon" + ], + "additionalProperties": false, + "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." + }, + "Steps": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/StepsItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Step-by-step guide" + }, + "StepsItem": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "details": { + "type": "string" + } + }, + "required": [ + "title", + "details" + ], + "additionalProperties": false, + "description": "title and details text for one step" + }, + "InlineHeader": { + "type": "object", + "properties": { + "heading": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "heading" + ], + "additionalProperties": false, + "description": "Compact section heading with an optional one-line description, for use inside cards." + }, + "EntityList": { + "type": "object", + "properties": { + "rows": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + } + }, + "size": { + "default": "default", + "type": "string", + "enum": [ + "small", + "default" + ] + }, + "header": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + }, + "footer": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + } + }, + "required": [ + "rows", + "size" + ], + "additionalProperties": false, + "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." + }, + "EditableTable": { + "type": "object", + "properties": { + "name": { + "default": "", + "type": "string" + }, + "columns": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "text", + "number", + "date-single", + "select", + "url" + ] + }, + "key": { + "default": "default", + "type": "string" + }, + "header": { + "default": "", + "type": "string" + }, + "width": { + "type": "number" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false + } + } + }, + "required": [ + "type", + "key", + "header" + ], + "additionalProperties": false + } + }, + "data": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + } + }, + "required": [ + "id", + "values" + ], + "additionalProperties": false + } + } + }, + "required": [ + "name", + "columns", + "data" + ], + "additionalProperties": false, + "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" + }, + "SnippetCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/SnippetCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." + }, + "SnippetCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "lhs": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + } + ] + }, + "rhs": { + "anyOf": [ + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/BoldText" + } + ] + } + }, + "required": [ + "lhs" + ], + "additionalProperties": false, + "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." + }, + "IconText": { + "type": "object", + "properties": { + "icon": { + "$ref": "#/$defs/Icon" + }, + "iconVariant": { + "default": "neutral", + "type": "string", + "enum": [ + "neutral", + "info", + "success", + "warning", + "danger", + "inverted", + "filled", + "soft" + ] + }, + "iconSize": { + "default": "m", + "type": "string", + "enum": [ + "xs", + "s", + "m", + "l", + "xl", + "sm", + "md", + "lg" + ] + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + }, + "layout": { + "default": "horizontal", + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + } + }, + "required": [ + "icon", + "iconVariant", + "iconSize", + "title", + "bold", + "layout" + ], + "additionalProperties": false, + "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." + }, + "ImageText": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + }, + "layout": { + "default": "horizontal", + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + }, + "imageSize": { + "type": "number" + } + }, + "required": [ + "src", + "title", + "bold", + "layout" + ], + "additionalProperties": false, + "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." + }, + "Text": { + "type": "object", + "properties": { + "variant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + }, + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "subtextVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number", + "metric" + ] + }, + "size": { + "default": "sm", + "type": "string", + "enum": [ + "xs", + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "variant", + "value", + "subtextVariant", + "size" + ], + "additionalProperties": false, + "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "BoldText": { + "type": "object", + "properties": { + "variant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + }, + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "subtextVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number", + "metric" + ] + }, + "size": { + "default": "sm", + "type": "string", + "enum": [ + "xs", + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "variant", + "value", + "subtextVariant", + "size" + ], + "additionalProperties": false, + "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "OverviewCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/OverviewCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." + }, + "OverviewCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "top": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + }, + { + "$ref": "#/$defs/Text" + } + ] + }, + "bottom": { + "$ref": "#/$defs/MetricIndicatorInline" + } + }, + "required": [ + "top" + ], + "additionalProperties": false, + "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." + }, + "MetricIndicatorInline": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "trend": { + "type": "object", + "properties": { + "direction": { + "type": "string", + "enum": [ + "up", + "down" + ] + }, + "value": { + "type": "number" + } + }, + "required": [ + "direction", + "value" + ], + "additionalProperties": false + } + }, + "required": [ + "value" + ], + "additionalProperties": false, + "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." + }, + "ContextCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/ContextCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." + }, + "ContextCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/Tag" + } + ] + }, + "body": { + "type": "string" + }, + "bgColor": { + "type": "string", + "enum": [ + "gray" + ] + }, + "bgImageSrc": { + "type": "string" + }, + "bgImageAlt": { + "type": "string" + } + }, + "required": [ + "title" + ], + "additionalProperties": false, + "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." + }, + "Tag": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + }, + "variant": { + "type": "string", + "enum": [ + "neutral", + "info", + "success", + "warning", + "danger" + ] + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Styled tag/badge with optional Icon and variant" + }, + "CompositeCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/CompositeCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." + }, + "CompositeCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "header": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + }, + { + "$ref": "#/$defs/ImageTextLarge" + }, + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/Image" + } + ] + }, + "body": { + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/BoldText" + }, + { + "$ref": "#/$defs/MetricIndicatorInline" + }, + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/ListBlock" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/EntityList" + } + ] + } + }, + "footer": { + "type": "object", + "properties": { + "price": { + "anyOf": [ + { + "$ref": "#/$defs/BoldText" + }, + { + "$ref": "#/$defs/MetricIndicatorWithStrikethrough" + } + ] + }, + "button": { + "$ref": "#/$defs/Button" + } + }, + "additionalProperties": false + } + }, + "required": [ + "body" + ], + "additionalProperties": false, + "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." + }, + "ImageTextLarge": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + } + }, + "required": [ + "src", + "title", + "bold" + ], + "additionalProperties": false, + "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." + }, + "ListBlock": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/ListItem" + } + }, + "variant": { + "type": "string", + "enum": [ + "number", + "image" + ] + }, + "size": { + "type": "string", + "enum": [ + "default", + "small" + ] + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." + }, + "ListItem": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "image": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + } + }, + "required": [ + "src", + "alt" + ], + "additionalProperties": false + }, + "actionLabel": { + "type": "string" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "title" + ], + "additionalProperties": false, + "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." + }, + "MetricIndicatorWithStrikethrough": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "previousValue": { + "type": "string" + }, + "trend": { + "type": "object", + "properties": { + "direction": { + "type": "string", + "enum": [ + "up", + "down" + ] + }, + "value": { + "type": "number" + } + }, + "required": [ + "direction", + "value" + ], + "additionalProperties": false + } + }, + "required": [ + "value" + ], + "additionalProperties": false, + "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." + }, + "VisualCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/VisualCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." + }, + "VisualCardItem": { + "type": "object", + "properties": { + "body": { + "$ref": "#/$defs/BoldText" + }, + "id": { + "type": "string" + }, + "bgImageSrc": { + "type": "string" + }, + "tag": { + "$ref": "#/$defs/Tag" + }, + "bgImageAlt": { + "type": "string" + } + }, + "required": [ + "body" + ], + "additionalProperties": false, + "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." + }, + "Tabs": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/TabItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Tabbed container" + }, + "TabItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trigger": { + "type": "string" + }, + "content": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + } + }, + "required": [ + "value", + "trigger", + "content" + ], + "additionalProperties": false, + "description": "value is unique id, trigger is tab label, content is array of components" + }, + "Carousel": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + } + }, + "variant": { + "type": "string", + "enum": [ + "card", + "sunk" + ] + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Horizontal scrollable carousel" + }, + "Stack": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": {} + }, + "direction": { + "type": "string", + "enum": [ + "row", + "column" + ] + }, + "gap": { + "type": "string", + "enum": [ + "none", + "xs", + "s", + "m", + "l", + "xl", + "2xl" + ] + }, + "align": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "stretch", + "baseline" + ] + }, + "justify": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "between", + "around", + "evenly" + ] + }, + "wrap": { + "type": "boolean" + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." + }, + "Slice": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "value": { + "type": "number" + } + }, + "required": [ + "category", + "value" + ], + "additionalProperties": false, + "description": "One slice with label and numeric value" + }, + "Label": { + "type": "object", + "properties": { + "text": { + "type": "string" + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Text label" + }, + "SwitchGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/SwitchItem" + } + }, + "variant": { + "type": "string", + "enum": [ + "clear", + "card", + "sunk" + ] + }, + "value": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false, + "description": "Group of switch toggles" + }, + "SwitchItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "defaultChecked": { + "type": "boolean" + } + }, + "required": [ + "name" + ], + "additionalProperties": false, + "description": "Individual switch toggle" + }, + "Accordion": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/AccordionItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Collapsible sections" + }, + "AccordionItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trigger": { + "type": "string" + }, + "content": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + } + }, + "required": [ + "value", + "trigger", + "content" + ], + "additionalProperties": false, + "description": "value is unique id, trigger is section title" + }, + "Modal": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "open": { + "type": "boolean" + }, + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "title", + "children" + ], + "additionalProperties": false, + "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." + } + } + }, + "examples": [ + "Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]", + "Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])", + "Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])", + "Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]", + "Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")", + "Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])" + ], + "additionalRules": [ + "When asked about data, generate realistic/plausible data", + "For grid-like layouts, use Stack with direction \"row\" and wrap=true. Avoid justify=\"between\" unless you specifically want large gutters.", + "For forms, define one FormControl reference per field so controls can stream progressively.", + "For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).", + "Never nest Form inside Form.", + "Use @Reset($var1, $var2) after form submit to restore defaults — not @Set($var, \"\")", + "Multi-query refresh: Action([@Run(mutation), @Run(query1), @Run(query2), @Reset(...)])", + "$variables are reactive: changing via Select or @Set re-evaluates all Queries and expressions referencing them", + "Use existing components (Tabs, Accordion, Modal) before inventing ternary show/hide patterns", + "Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items; every item in a block must have the same structure.", + "Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicatorInline / MetricIndicatorWithStrikethrough are inline building blocks used INSIDE card items — do not place them directly in a Stack or Card.", + "EntityList size='small' (no header/footer) is only for use inside a CompositeCardItem body; use size='default' everywhere else.", + "Image URLs must be real (from a tool result or the user) — never invent or template an image URL.", + "Always pass a category to Icon — it enables a topical fallback when the exact icon name is unavailable.", + "EditableTable requires the consuming app to persist edits — use it only when the user or app explicitly asks for an editable table; default to Table for read-only data." + ] + }, + "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Stack(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Layout\nStack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean) — Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\".\nTabs(items: TabItem[]) — Tabbed container\nTabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[]) — value is unique id, trigger is tab label, content is array of components\nAccordion(items: AccordionItem[]) — Collapsible sections\nAccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[]) — value is unique id, trigger is section title\nSteps(items: StepsItem[]) — Step-by-step guide\nStepsItem(title: string, details: string) — title and details text for one step\nCarousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\") — Horizontal scrollable carousel\nSeparator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean) — Visual divider between content sections\nModal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\") — Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children.\n- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.\n- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.\n- Use nested Stacks when you need explicit rows/sections.\n- Show/hide sections: $editId != \"\" ? Card([editForm]) : null\n- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.\n- Use Tabs for alternative views (chart types, data sections) — no $variable needed\n- Shared filter across Tabs: same $days binding in Query args works across all TabItems\n\n### Content\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean) — Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts.\nCardHeader(title?: string, subtitle?: string) — Header with optional title and subtitle\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nMarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\") — Renders markdown text with optional container variant\nCallout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding) — Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.\nTextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string) — Text callout with variant, title, and description\nImage(alt: string, src?: string) — Image with alt text and optional URL\nImageBlock(src: string, alt?: string) — Image block with loading state\nImageGallery(images: {src: string, alt?: string, details?: string}[]) — Gallery grid of images with modal preview\nCodeBlock(language: string, codeString: string) — Syntax-highlighted code block\nInlineHeader(heading: string, description?: string) — Compact section heading with an optional one-line description, for use inside cards.\n- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).\n- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.\n- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null\n- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])\n\n### Tables\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\nEditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[]) — Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field\n- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).\n- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.\n- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName\n- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))\n- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))\n- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data\n- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input\n- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts\n- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")\n\n### Charts (2D)\nBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number) — Vertical bars; use for comparing values across categories with one or more series\nLineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Lines over categories; use for trends and continuous data over time\nAreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Filled area under lines; use for cumulative totals or volume trends over time\nRadarChart(labels: string[], series: Series[]) — Spider/web chart; use for comparing multiple variables across one or more entities\nHorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string) — Horizontal bars; prefer when category labels are long or for ranked lists\nSeries(category: string, values: number[]) — One data series\n- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])\n- Use Cards to wrap charts with CardHeader for titled sections\n- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data\n- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])\n\n### Charts (1D)\nPieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\") — Circular slices; use plucked arrays: PieChart(data.categories, data.values)\nRadialChart(labels: string[], values: number[]) — Radial bars; use plucked arrays: RadialChart(data.categories, data.values)\nSingleStackedBarChart(labels: string[], values: number[]) — Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)\nSlice(category: string, value: number) — One slice with label and numeric value\n- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:\n- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`\n- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`\n\n### Charts (Scatter)\nScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string) — X/Y scatter plot; use for correlations, distributions, and clustering\nScatterSeries(name: string, points: Point[]) — Named dataset\nPoint(x: number, y: number, z?: number) — Data point with numeric coordinates\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nLabel(text: string) — Text label\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nTextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nDatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSlider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding) — Numeric slider input; supports continuous and discrete (stepped) variants\nCheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)\nCheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)\nRadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nRadioItem(label: string, description: string, value: string)\nSwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>) — Group of switch toggles\nSwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean) — Individual switch toggle\nChips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.\nChipItem(value: string, label: string, icon?: Icon, disabled?: boolean) — A single selectable chip inside a Chips group, with a value, label and optional icon.\nOptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.\nOptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean) — A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.\n- Chips: compact single/multiple selection pills. Use ChipItem references for each option.\n- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.\n- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.\n- NEVER nest Form inside Form — each Form should be a standalone container.\n- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.\n- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}\n- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric\n- The renderer shows error messages automatically — do NOT generate error text in the UI\n- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField\n- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal.\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nIconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\") — Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.\n- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.\n- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))\n\n### Data Display\nTagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\") — tags is an array of strings; optional size sm | md | lg\nTag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\") — Styled tag/badge with optional Icon and variant\nIcon(name: string, category?: string) — A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.\nEntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}) — Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.\nListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\") — A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.\nListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression) — Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.\n- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")\n- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.\n- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional.\n\n### Cards\nSnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.\nSnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText) — One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).\nOverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.\nOverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline) — One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.\nContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.\nContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string) — A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.\nCompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.\nCompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button}) — A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.\nVisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.\nVisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string) — A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).\nText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nBoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nIconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\") — An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.\nImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number) — A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.\nImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean) — A full-width banner image above a bold title and optional subtitle. src must be a real image URL.\nMetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional +/- percentage trend and subtext, all on one line.\nMetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.\n- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.\n- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.\n- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.\n- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.\n- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.\n- VisualCardItem: image-first card with a BoldText body and optional Tag.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Stack(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Stack(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n\n## Examples\n\nExample 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]\n\nExample 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])\n\nExample 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])\n\nExample 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]\n\nExample 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")\n\nExample 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])\n\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Stack(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n\n- When asked about data, generate realistic/plausible data\n- For grid-like layouts, use Stack with direction \"row\" and wrap=true. Avoid justify=\"between\" unless you specifically want large gutters.\n- For forms, define one FormControl reference per field so controls can stream progressively.\n- For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).\n- Never nest Form inside Form.\n- Use @Reset($var1, $var2) after form submit to restore defaults — not @Set($var, \"\")\n- Multi-query refresh: Action([@Run(mutation), @Run(query1), @Run(query2), @Reset(...)])\n- $variables are reactive: changing via Select or @Set re-evaluates all Queries and expressions referencing them\n- Use existing components (Tabs, Accordion, Modal) before inventing ternary show/hide patterns\n- Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items; every item in a block must have the same structure.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicatorInline / MetricIndicatorWithStrikethrough are inline building blocks used INSIDE card items — do not place them directly in a Stack or Card.\n- EntityList size='small' (no header/footer) is only for use inside a CompositeCardItem body; use size='default' everywhere else.\n- Image URLs must be real (from a tool result or the user) — never invent or template an image URL.\n- Always pass a category to Icon — it enables a topical fallback when the exact icon name is unavailable.\n- EditableTable requires the consuming app to persist edits — use it only when the user or app explicitly asks for an editable table; default to Table for read-only data." + }, { "name": "slice-bindings", "spec": { diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json index e81a3102db..1edd8a7193 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json @@ -4251,6 +4251,4259 @@ ] } }, + "openui": { + "schema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "Card": { + "$ref": "#/$defs/Card" + }, + "CardHeader": { + "$ref": "#/$defs/CardHeader" + }, + "TextContent": { + "$ref": "#/$defs/TextContent" + }, + "MarkDownRenderer": { + "$ref": "#/$defs/MarkDownRenderer" + }, + "Callout": { + "$ref": "#/$defs/Callout" + }, + "TextCallout": { + "$ref": "#/$defs/TextCallout" + }, + "Image": { + "$ref": "#/$defs/Image" + }, + "ImageBlock": { + "$ref": "#/$defs/ImageBlock" + }, + "ImageGallery": { + "$ref": "#/$defs/ImageGallery" + }, + "CodeBlock": { + "$ref": "#/$defs/CodeBlock" + }, + "InlineHeader": { + "$ref": "#/$defs/InlineHeader" + }, + "Table": { + "$ref": "#/$defs/Table" + }, + "Col": { + "$ref": "#/$defs/Col" + }, + "EditableTable": { + "$ref": "#/$defs/EditableTable" + }, + "BarChart": { + "$ref": "#/$defs/BarChart" + }, + "LineChart": { + "$ref": "#/$defs/LineChart" + }, + "AreaChart": { + "$ref": "#/$defs/AreaChart" + }, + "RadarChart": { + "$ref": "#/$defs/RadarChart" + }, + "HorizontalBarChart": { + "$ref": "#/$defs/HorizontalBarChart" + }, + "Series": { + "$ref": "#/$defs/Series" + }, + "PieChart": { + "$ref": "#/$defs/PieChart" + }, + "RadialChart": { + "$ref": "#/$defs/RadialChart" + }, + "SingleStackedBarChart": { + "$ref": "#/$defs/SingleStackedBarChart" + }, + "Slice": { + "$ref": "#/$defs/Slice" + }, + "ScatterChart": { + "$ref": "#/$defs/ScatterChart" + }, + "ScatterSeries": { + "$ref": "#/$defs/ScatterSeries" + }, + "Point": { + "$ref": "#/$defs/Point" + }, + "Form": { + "$ref": "#/$defs/Form" + }, + "FormControl": { + "$ref": "#/$defs/FormControl" + }, + "Label": { + "$ref": "#/$defs/Label" + }, + "Input": { + "$ref": "#/$defs/Input" + }, + "TextArea": { + "$ref": "#/$defs/TextArea" + }, + "Select": { + "$ref": "#/$defs/Select" + }, + "SelectItem": { + "$ref": "#/$defs/SelectItem" + }, + "DatePicker": { + "$ref": "#/$defs/DatePicker" + }, + "Slider": { + "$ref": "#/$defs/Slider" + }, + "CheckBoxGroup": { + "$ref": "#/$defs/CheckBoxGroup" + }, + "CheckBoxItem": { + "$ref": "#/$defs/CheckBoxItem" + }, + "RadioGroup": { + "$ref": "#/$defs/RadioGroup" + }, + "RadioItem": { + "$ref": "#/$defs/RadioItem" + }, + "SwitchGroup": { + "$ref": "#/$defs/SwitchGroup" + }, + "SwitchItem": { + "$ref": "#/$defs/SwitchItem" + }, + "ChipItem": { + "$ref": "#/$defs/ChipItem" + }, + "Chips": { + "$ref": "#/$defs/Chips" + }, + "OptionCard": { + "$ref": "#/$defs/OptionCard" + }, + "OptionCards": { + "$ref": "#/$defs/OptionCards" + }, + "Button": { + "$ref": "#/$defs/Button" + }, + "Buttons": { + "$ref": "#/$defs/Buttons" + }, + "IconButton": { + "$ref": "#/$defs/IconButton" + }, + "Stack": { + "$ref": "#/$defs/Stack" + }, + "Tabs": { + "$ref": "#/$defs/Tabs" + }, + "TabItem": { + "$ref": "#/$defs/TabItem" + }, + "Accordion": { + "$ref": "#/$defs/Accordion" + }, + "AccordionItem": { + "$ref": "#/$defs/AccordionItem" + }, + "Steps": { + "$ref": "#/$defs/Steps" + }, + "StepsItem": { + "$ref": "#/$defs/StepsItem" + }, + "Carousel": { + "$ref": "#/$defs/Carousel" + }, + "Separator": { + "$ref": "#/$defs/Separator" + }, + "TagBlock": { + "$ref": "#/$defs/TagBlock" + }, + "Tag": { + "$ref": "#/$defs/Tag" + }, + "Icon": { + "$ref": "#/$defs/Icon" + }, + "EntityList": { + "$ref": "#/$defs/EntityList" + }, + "ListBlock": { + "$ref": "#/$defs/ListBlock" + }, + "ListItem": { + "$ref": "#/$defs/ListItem" + }, + "Text": { + "$ref": "#/$defs/Text" + }, + "BoldText": { + "$ref": "#/$defs/BoldText" + }, + "IconText": { + "$ref": "#/$defs/IconText" + }, + "ImageText": { + "$ref": "#/$defs/ImageText" + }, + "ImageTextLarge": { + "$ref": "#/$defs/ImageTextLarge" + }, + "MetricIndicatorInline": { + "$ref": "#/$defs/MetricIndicatorInline" + }, + "MetricIndicatorWithStrikethrough": { + "$ref": "#/$defs/MetricIndicatorWithStrikethrough" + }, + "SnippetCardItem": { + "$ref": "#/$defs/SnippetCardItem" + }, + "SnippetCardBlock": { + "$ref": "#/$defs/SnippetCardBlock" + }, + "OverviewCardItem": { + "$ref": "#/$defs/OverviewCardItem" + }, + "OverviewCardBlock": { + "$ref": "#/$defs/OverviewCardBlock" + }, + "ContextCardItem": { + "$ref": "#/$defs/ContextCardItem" + }, + "ContextCardBlock": { + "$ref": "#/$defs/ContextCardBlock" + }, + "CompositeCardItem": { + "$ref": "#/$defs/CompositeCardItem" + }, + "CompositeCardBlock": { + "$ref": "#/$defs/CompositeCardBlock" + }, + "VisualCardItem": { + "$ref": "#/$defs/VisualCardItem" + }, + "VisualCardBlock": { + "$ref": "#/$defs/VisualCardBlock" + }, + "Modal": { + "$ref": "#/$defs/Modal" + } + }, + "required": [ + "Card", + "CardHeader", + "TextContent", + "MarkDownRenderer", + "Callout", + "TextCallout", + "Image", + "ImageBlock", + "ImageGallery", + "CodeBlock", + "InlineHeader", + "Table", + "Col", + "EditableTable", + "BarChart", + "LineChart", + "AreaChart", + "RadarChart", + "HorizontalBarChart", + "Series", + "PieChart", + "RadialChart", + "SingleStackedBarChart", + "Slice", + "ScatterChart", + "ScatterSeries", + "Point", + "Form", + "FormControl", + "Label", + "Input", + "TextArea", + "Select", + "SelectItem", + "DatePicker", + "Slider", + "CheckBoxGroup", + "CheckBoxItem", + "RadioGroup", + "RadioItem", + "SwitchGroup", + "SwitchItem", + "ChipItem", + "Chips", + "OptionCard", + "OptionCards", + "Button", + "Buttons", + "IconButton", + "Stack", + "Tabs", + "TabItem", + "Accordion", + "AccordionItem", + "Steps", + "StepsItem", + "Carousel", + "Separator", + "TagBlock", + "Tag", + "Icon", + "EntityList", + "ListBlock", + "ListItem", + "Text", + "BoldText", + "IconText", + "ImageText", + "ImageTextLarge", + "MetricIndicatorInline", + "MetricIndicatorWithStrikethrough", + "SnippetCardItem", + "SnippetCardBlock", + "OverviewCardItem", + "OverviewCardBlock", + "ContextCardItem", + "ContextCardBlock", + "CompositeCardItem", + "CompositeCardBlock", + "VisualCardItem", + "VisualCardBlock", + "Modal" + ], + "additionalProperties": false, + "$defs": { + "Card": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + }, + { + "$ref": "#/$defs/Tabs" + }, + { + "$ref": "#/$defs/Carousel" + }, + { + "$ref": "#/$defs/Stack" + } + ] + } + }, + "variant": { + "type": "string", + "enum": [ + "card", + "sunk", + "clear" + ] + }, + "direction": { + "type": "string", + "enum": [ + "row", + "column" + ] + }, + "gap": { + "type": "string", + "enum": [ + "none", + "xs", + "s", + "m", + "l", + "xl", + "2xl" + ] + }, + "align": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "stretch", + "baseline" + ] + }, + "justify": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "between", + "around", + "evenly" + ] + }, + "wrap": { + "type": "boolean" + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." + }, + "TextContent": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "size": { + "type": "string", + "enum": [ + "small", + "default", + "large", + "small-heavy", + "large-heavy" + ] + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." + }, + "MarkDownRenderer": { + "type": "object", + "properties": { + "textMarkdown": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": [ + "clear", + "card", + "sunk" + ] + } + }, + "required": [ + "textMarkdown" + ], + "additionalProperties": false, + "description": "Renders markdown text with optional container variant" + }, + "CardHeader": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + } + }, + "additionalProperties": false, + "description": "Header with optional title and subtitle" + }, + "Callout": { + "type": "object", + "properties": { + "variant": { + "type": "string", + "enum": [ + "info", + "warning", + "error", + "success", + "neutral" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "visible": { + "type": "boolean" + } + }, + "required": [ + "variant", + "title", + "description" + ], + "additionalProperties": false, + "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." + }, + "TextCallout": { + "type": "object", + "properties": { + "variant": { + "type": "string", + "enum": [ + "neutral", + "info", + "warning", + "success", + "danger" + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false, + "description": "Text callout with variant, title, and description" + }, + "CodeBlock": { + "type": "object", + "properties": { + "language": { + "type": "string" + }, + "codeString": { + "type": "string" + } + }, + "required": [ + "language", + "codeString" + ], + "additionalProperties": false, + "description": "Syntax-highlighted code block" + }, + "Image": { + "type": "object", + "properties": { + "alt": { + "type": "string" + }, + "src": { + "type": "string" + } + }, + "required": [ + "alt" + ], + "additionalProperties": false, + "description": "Image with alt text and optional URL" + }, + "ImageBlock": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + } + }, + "required": [ + "src" + ], + "additionalProperties": false, + "description": "Image block with loading state" + }, + "ImageGallery": { + "type": "object", + "properties": { + "images": { + "type": "array", + "items": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "details": { + "type": "string" + } + }, + "required": [ + "src" + ], + "additionalProperties": false + } + } + }, + "required": [ + "images" + ], + "additionalProperties": false, + "description": "Gallery grid of images with modal preview" + }, + "Separator": { + "type": "object", + "properties": { + "orientation": { + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + }, + "decorative": { + "type": "boolean" + } + }, + "additionalProperties": false, + "description": "Visual divider between content sections" + }, + "HorizontalBarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "grouped", + "stacked" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Horizontal bars; prefer when category labels are long or for ranked lists" + }, + "Series": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "category", + "values" + ], + "additionalProperties": false, + "description": "One data series" + }, + "RadarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Spider/web chart; use for comparing multiple variables across one or more entities" + }, + "PieChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + }, + "variant": { + "type": "string", + "enum": [ + "pie", + "donut" + ] + }, + "appearance": { + "type": "string", + "enum": [ + "circular", + "semiCircular" + ] + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" + }, + "RadialChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" + }, + "SingleStackedBarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "values": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "labels", + "values" + ], + "additionalProperties": false, + "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" + }, + "ScatterChart": { + "type": "object", + "properties": { + "datasets": { + "type": "array", + "items": { + "$ref": "#/$defs/ScatterSeries" + } + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + } + }, + "required": [ + "datasets" + ], + "additionalProperties": false, + "description": "X/Y scatter plot; use for correlations, distributions, and clustering" + }, + "ScatterSeries": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "points": { + "type": "array", + "items": { + "$ref": "#/$defs/Point" + } + } + }, + "required": [ + "name", + "points" + ], + "additionalProperties": false, + "description": "Named dataset" + }, + "Point": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "z": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ], + "additionalProperties": false, + "description": "Data point with numeric coordinates" + }, + "AreaChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "linear", + "natural", + "step" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Filled area under lines; use for cumulative totals or volume trends over time" + }, + "BarChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "grouped", + "stacked" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Vertical bars; use for comparing values across categories with one or more series" + }, + "LineChart": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "series": { + "type": "array", + "items": { + "$ref": "#/$defs/Series" + } + }, + "variant": { + "type": "string", + "enum": [ + "linear", + "natural", + "step" + ] + }, + "xLabel": { + "type": "string" + }, + "yLabel": { + "type": "string" + }, + "height": { + "type": "number" + } + }, + "required": [ + "labels", + "series" + ], + "additionalProperties": false, + "description": "Lines over categories; use for trends and continuous data over time" + }, + "Table": { + "type": "object", + "properties": { + "columns": { + "type": "array", + "items": { + "$ref": "#/$defs/Col" + } + } + }, + "required": [ + "columns" + ], + "additionalProperties": false, + "description": "Data table — column-oriented. Each Col holds its own data array." + }, + "Col": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "data": {}, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "action" + ] + } + }, + "required": [ + "label", + "data" + ], + "additionalProperties": false, + "description": "Column definition — holds label + data array" + }, + "TagBlock": { + "type": "object", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "tags" + ], + "additionalProperties": false, + "description": "tags is an array of strings; optional size sm | md | lg" + }, + "Form": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "buttons": { + "$ref": "#/$defs/Buttons" + }, + "fields": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/FormControl" + } + } + }, + "required": [ + "name", + "buttons", + "fields" + ], + "additionalProperties": false, + "description": "Form container with fields and explicit action buttons" + }, + "Buttons": { + "type": "object", + "properties": { + "buttons": { + "type": "array", + "items": { + "$ref": "#/$defs/Button" + } + }, + "direction": { + "type": "string", + "enum": [ + "row", + "column" + ] + } + }, + "required": [ + "buttons" + ], + "additionalProperties": false, + "description": "Group of Button components. direction: \"row\" (default) | \"column\"." + }, + "Button": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "variant": { + "type": "string", + "enum": [ + "primary", + "secondary", + "tertiary" + ] + }, + "type": { + "type": "string", + "enum": [ + "normal", + "destructive" + ] + }, + "size": { + "type": "string", + "enum": [ + "extra-small", + "small", + "medium", + "large" + ] + } + }, + "required": [ + "label" + ], + "additionalProperties": false, + "description": "Clickable button" + }, + "FormControl": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "input": { + "anyOf": [ + { + "$ref": "#/$defs/Input" + }, + { + "$ref": "#/$defs/TextArea" + }, + { + "$ref": "#/$defs/Select" + }, + { + "$ref": "#/$defs/DatePicker" + }, + { + "$ref": "#/$defs/Slider" + }, + { + "$ref": "#/$defs/CheckBoxGroup" + }, + { + "$ref": "#/$defs/RadioGroup" + }, + { + "$ref": "#/$defs/Chips" + }, + { + "$ref": "#/$defs/OptionCards" + } + ] + }, + "hint": { + "type": "string" + } + }, + "required": [ + "label", + "input" + ], + "additionalProperties": false, + "description": "Field with label, input component, and optional hint text" + }, + "Input": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "placeholder": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "text", + "email", + "password", + "number", + "url" + ] + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "TextArea": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "placeholder": { + "type": "string" + }, + "rows": { + "type": "number" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "Select": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/SelectItem" + } + }, + "placeholder": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + }, + "size": { + "type": "string", + "enum": [ + "small", + "medium", + "large" + ] + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "SelectItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false, + "description": "Option for Select" + }, + "DatePicker": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "mode": { + "type": "string", + "enum": [ + "single", + "range" + ] + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": {} + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "Slider": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": [ + "continuous", + "discrete" + ] + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "step": { + "type": "number" + }, + "defaultValue": { + "type": "array", + "items": { + "type": "number" + } + }, + "label": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "required": [ + "name", + "variant", + "min", + "max" + ], + "additionalProperties": false, + "description": "Numeric slider input; supports continuous and discrete (stepped) variants" + }, + "CheckBoxGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/CheckBoxItem" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "CheckBoxItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "defaultChecked": { + "type": "boolean" + } + }, + "required": [ + "label", + "description", + "name" + ], + "additionalProperties": false + }, + "RadioGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/RadioItem" + } + }, + "defaultValue": { + "type": "string" + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false + }, + "RadioItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "description", + "value" + ], + "additionalProperties": false + }, + "Chips": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "default": "multiple", + "type": "string", + "enum": [ + "single", + "multiple" + ] + }, + "items": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/ChipItem" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "defaultValue": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "name", + "type", + "items" + ], + "additionalProperties": false, + "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." + }, + "ChipItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "disabled": { + "type": "boolean" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false, + "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." + }, + "Icon": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "category": { + "type": "string" + } + }, + "required": [ + "name" + ], + "additionalProperties": false, + "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." + }, + "OptionCards": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "default": "single", + "type": "string", + "enum": [ + "single", + "multiple" + ] + }, + "items": { + "default": [], + "type": "array", + "items": { + "$ref": "#/$defs/OptionCard" + } + }, + "rules": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "email": { + "type": "boolean" + }, + "url": { + "type": "boolean" + }, + "numeric": { + "type": "boolean" + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "minLength": { + "type": "number" + }, + "maxLength": { + "type": "number" + }, + "pattern": { + "type": "string" + } + }, + "additionalProperties": false + }, + "defaultValue": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "name", + "type", + "items" + ], + "additionalProperties": false, + "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." + }, + "OptionCard": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "topContent": { + "anyOf": [ + { + "$ref": "#/$defs/Icon" + }, + { + "$ref": "#/$defs/Image" + } + ] + }, + "disabled": { + "type": "boolean" + } + }, + "required": [ + "value", + "title" + ], + "additionalProperties": false, + "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." + }, + "IconButton": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "variant": { + "type": "string", + "enum": [ + "primary", + "secondary", + "tertiary" + ] + }, + "size": { + "type": "string", + "enum": [ + "extra-small", + "small", + "medium", + "large" + ] + }, + "shape": { + "type": "string", + "enum": [ + "square", + "circle" + ] + } + }, + "required": [ + "name", + "icon" + ], + "additionalProperties": false, + "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." + }, + "Steps": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/StepsItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Step-by-step guide" + }, + "StepsItem": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "details": { + "type": "string" + } + }, + "required": [ + "title", + "details" + ], + "additionalProperties": false, + "description": "title and details text for one step" + }, + "InlineHeader": { + "type": "object", + "properties": { + "heading": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "heading" + ], + "additionalProperties": false, + "description": "Compact section heading with an optional one-line description, for use inside cards." + }, + "EntityList": { + "type": "object", + "properties": { + "rows": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + } + }, + "size": { + "default": "default", + "type": "string", + "enum": [ + "small", + "default" + ] + }, + "header": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + }, + "footer": { + "type": "object", + "properties": { + "left": { + "type": "string" + }, + "right": { + "type": "string" + }, + "rightVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + } + }, + "required": [ + "left", + "right", + "rightVariant" + ], + "additionalProperties": false + } + }, + "required": [ + "rows", + "size" + ], + "additionalProperties": false, + "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." + }, + "EditableTable": { + "type": "object", + "properties": { + "name": { + "default": "", + "type": "string" + }, + "columns": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "text", + "number", + "date-single", + "select", + "url" + ] + }, + "key": { + "default": "default", + "type": "string" + }, + "header": { + "default": "", + "type": "string" + }, + "width": { + "type": "number" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "value", + "label" + ], + "additionalProperties": false + } + } + }, + "required": [ + "type", + "key", + "header" + ], + "additionalProperties": false + } + }, + "data": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + } + }, + "required": [ + "id", + "values" + ], + "additionalProperties": false + } + } + }, + "required": [ + "name", + "columns", + "data" + ], + "additionalProperties": false, + "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" + }, + "SnippetCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/SnippetCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." + }, + "SnippetCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "lhs": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + } + ] + }, + "rhs": { + "anyOf": [ + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/BoldText" + } + ] + } + }, + "required": [ + "lhs" + ], + "additionalProperties": false, + "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." + }, + "IconText": { + "type": "object", + "properties": { + "icon": { + "$ref": "#/$defs/Icon" + }, + "iconVariant": { + "default": "neutral", + "type": "string", + "enum": [ + "neutral", + "info", + "success", + "warning", + "danger", + "inverted", + "filled", + "soft" + ] + }, + "iconSize": { + "default": "m", + "type": "string", + "enum": [ + "xs", + "s", + "m", + "l", + "xl", + "sm", + "md", + "lg" + ] + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + }, + "layout": { + "default": "horizontal", + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + } + }, + "required": [ + "icon", + "iconVariant", + "iconSize", + "title", + "bold", + "layout" + ], + "additionalProperties": false, + "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." + }, + "ImageText": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + }, + "layout": { + "default": "horizontal", + "type": "string", + "enum": [ + "horizontal", + "vertical" + ] + }, + "imageSize": { + "type": "number" + } + }, + "required": [ + "src", + "title", + "bold", + "layout" + ], + "additionalProperties": false, + "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." + }, + "Text": { + "type": "object", + "properties": { + "variant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + }, + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "subtextVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number", + "metric" + ] + }, + "size": { + "default": "sm", + "type": "string", + "enum": [ + "xs", + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "variant", + "value", + "subtextVariant", + "size" + ], + "additionalProperties": false, + "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "BoldText": { + "type": "object", + "properties": { + "variant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number" + ] + }, + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "subtextVariant": { + "default": "text", + "type": "string", + "enum": [ + "text", + "number", + "metric" + ] + }, + "size": { + "default": "sm", + "type": "string", + "enum": [ + "xs", + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "variant", + "value", + "subtextVariant", + "size" + ], + "additionalProperties": false, + "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." + }, + "OverviewCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/OverviewCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." + }, + "OverviewCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "top": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + }, + { + "$ref": "#/$defs/Text" + } + ] + }, + "bottom": { + "$ref": "#/$defs/MetricIndicatorInline" + } + }, + "required": [ + "top" + ], + "additionalProperties": false, + "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." + }, + "MetricIndicatorInline": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "trend": { + "type": "object", + "properties": { + "direction": { + "type": "string", + "enum": [ + "up", + "down" + ] + }, + "value": { + "type": "number" + } + }, + "required": [ + "direction", + "value" + ], + "additionalProperties": false + } + }, + "required": [ + "value" + ], + "additionalProperties": false, + "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." + }, + "ContextCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/ContextCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." + }, + "ContextCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/Tag" + } + ] + }, + "body": { + "type": "string" + }, + "bgColor": { + "type": "string", + "enum": [ + "gray" + ] + }, + "bgImageSrc": { + "type": "string" + }, + "bgImageAlt": { + "type": "string" + } + }, + "required": [ + "title" + ], + "additionalProperties": false, + "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." + }, + "Tag": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "icon": { + "$ref": "#/$defs/Icon" + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + }, + "variant": { + "type": "string", + "enum": [ + "neutral", + "info", + "success", + "warning", + "danger" + ] + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Styled tag/badge with optional Icon and variant" + }, + "CompositeCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/CompositeCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." + }, + "CompositeCardItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "header": { + "anyOf": [ + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/ImageText" + }, + { + "$ref": "#/$defs/ImageTextLarge" + }, + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/Image" + } + ] + }, + "body": { + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/Text" + }, + { + "$ref": "#/$defs/BoldText" + }, + { + "$ref": "#/$defs/MetricIndicatorInline" + }, + { + "$ref": "#/$defs/IconText" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/ListBlock" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/EntityList" + } + ] + } + }, + "footer": { + "type": "object", + "properties": { + "price": { + "anyOf": [ + { + "$ref": "#/$defs/BoldText" + }, + { + "$ref": "#/$defs/MetricIndicatorWithStrikethrough" + } + ] + }, + "button": { + "$ref": "#/$defs/Button" + } + }, + "additionalProperties": false + } + }, + "required": [ + "body" + ], + "additionalProperties": false, + "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." + }, + "ImageTextLarge": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "bold": { + "default": false, + "type": "boolean" + } + }, + "required": [ + "src", + "title", + "bold" + ], + "additionalProperties": false, + "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." + }, + "ListBlock": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/ListItem" + } + }, + "variant": { + "type": "string", + "enum": [ + "number", + "image" + ] + }, + "size": { + "type": "string", + "enum": [ + "default", + "small" + ] + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." + }, + "ListItem": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "image": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "alt": { + "type": "string" + } + }, + "required": [ + "src", + "alt" + ], + "additionalProperties": false + }, + "actionLabel": { + "type": "string" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "title" + ], + "additionalProperties": false, + "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." + }, + "MetricIndicatorWithStrikethrough": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "previousValue": { + "type": "string" + }, + "trend": { + "type": "object", + "properties": { + "direction": { + "type": "string", + "enum": [ + "up", + "down" + ] + }, + "value": { + "type": "number" + } + }, + "required": [ + "direction", + "value" + ], + "additionalProperties": false + } + }, + "required": [ + "value" + ], + "additionalProperties": false, + "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." + }, + "VisualCardBlock": { + "type": "object", + "properties": { + "items": { + "minItems": 2, + "type": "array", + "items": { + "$ref": "#/$defs/VisualCardItem" + } + }, + "layout": { + "default": "grid", + "type": "string", + "enum": [ + "grid", + "carousel" + ] + }, + "responsive": { + "default": true, + "type": "boolean" + }, + "action": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "open_url" + }, + "url": { + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "continue_conversation" + }, + "context": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "params": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "gap": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "items", + "layout", + "responsive" + ], + "additionalProperties": false, + "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." + }, + "VisualCardItem": { + "type": "object", + "properties": { + "body": { + "$ref": "#/$defs/BoldText" + }, + "id": { + "type": "string" + }, + "bgImageSrc": { + "type": "string" + }, + "tag": { + "$ref": "#/$defs/Tag" + }, + "bgImageAlt": { + "type": "string" + } + }, + "required": [ + "body" + ], + "additionalProperties": false, + "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." + }, + "Tabs": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/TabItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Tabbed container" + }, + "TabItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trigger": { + "type": "string" + }, + "content": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + } + }, + "required": [ + "value", + "trigger", + "content" + ], + "additionalProperties": false, + "description": "value is unique id, trigger is tab label, content is array of components" + }, + "Carousel": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + } + }, + "variant": { + "type": "string", + "enum": [ + "card", + "sunk" + ] + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Horizontal scrollable carousel" + }, + "Stack": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": {} + }, + "direction": { + "type": "string", + "enum": [ + "row", + "column" + ] + }, + "gap": { + "type": "string", + "enum": [ + "none", + "xs", + "s", + "m", + "l", + "xl", + "2xl" + ] + }, + "align": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "stretch", + "baseline" + ] + }, + "justify": { + "type": "string", + "enum": [ + "start", + "center", + "end", + "between", + "around", + "evenly" + ] + }, + "wrap": { + "type": "boolean" + } + }, + "required": [ + "children" + ], + "additionalProperties": false, + "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." + }, + "Slice": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "value": { + "type": "number" + } + }, + "required": [ + "category", + "value" + ], + "additionalProperties": false, + "description": "One slice with label and numeric value" + }, + "Label": { + "type": "object", + "properties": { + "text": { + "type": "string" + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "description": "Text label" + }, + "SwitchGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/SwitchItem" + } + }, + "variant": { + "type": "string", + "enum": [ + "clear", + "card", + "sunk" + ] + }, + "value": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + } + }, + "required": [ + "name", + "items" + ], + "additionalProperties": false, + "description": "Group of switch toggles" + }, + "SwitchItem": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "defaultChecked": { + "type": "boolean" + } + }, + "required": [ + "name" + ], + "additionalProperties": false, + "description": "Individual switch toggle" + }, + "Accordion": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/AccordionItem" + } + } + }, + "required": [ + "items" + ], + "additionalProperties": false, + "description": "Collapsible sections" + }, + "AccordionItem": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "trigger": { + "type": "string" + }, + "content": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + } + }, + "required": [ + "value", + "trigger", + "content" + ], + "additionalProperties": false, + "description": "value is unique id, trigger is section title" + }, + "Modal": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "open": { + "type": "boolean" + }, + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/MarkDownRenderer" + }, + { + "$ref": "#/$defs/CardHeader" + }, + { + "$ref": "#/$defs/Callout" + }, + { + "$ref": "#/$defs/TextCallout" + }, + { + "$ref": "#/$defs/CodeBlock" + }, + { + "$ref": "#/$defs/Image" + }, + { + "$ref": "#/$defs/ImageBlock" + }, + { + "$ref": "#/$defs/ImageGallery" + }, + { + "$ref": "#/$defs/Separator" + }, + { + "$ref": "#/$defs/HorizontalBarChart" + }, + { + "$ref": "#/$defs/RadarChart" + }, + { + "$ref": "#/$defs/PieChart" + }, + { + "$ref": "#/$defs/RadialChart" + }, + { + "$ref": "#/$defs/SingleStackedBarChart" + }, + { + "$ref": "#/$defs/ScatterChart" + }, + { + "$ref": "#/$defs/AreaChart" + }, + { + "$ref": "#/$defs/BarChart" + }, + { + "$ref": "#/$defs/LineChart" + }, + { + "$ref": "#/$defs/Table" + }, + { + "$ref": "#/$defs/TagBlock" + }, + { + "$ref": "#/$defs/Form" + }, + { + "$ref": "#/$defs/Buttons" + }, + { + "$ref": "#/$defs/IconButton" + }, + { + "$ref": "#/$defs/Steps" + }, + { + "$ref": "#/$defs/InlineHeader" + }, + { + "$ref": "#/$defs/EntityList" + }, + { + "$ref": "#/$defs/EditableTable" + }, + { + "$ref": "#/$defs/SnippetCardBlock" + }, + { + "$ref": "#/$defs/OverviewCardBlock" + }, + { + "$ref": "#/$defs/ContextCardBlock" + }, + { + "$ref": "#/$defs/CompositeCardBlock" + }, + { + "$ref": "#/$defs/VisualCardBlock" + } + ] + } + }, + "size": { + "type": "string", + "enum": [ + "sm", + "md", + "lg" + ] + } + }, + "required": [ + "title", + "children" + ], + "additionalProperties": false, + "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." + } + } + }, + "root": "Stack", + "reactive": { + "Callout": [ + "visible" + ], + "Input": [ + "value" + ], + "TextArea": [ + "value" + ], + "Select": [ + "value" + ], + "DatePicker": [ + "value" + ], + "Slider": [ + "value" + ], + "CheckBoxGroup": [ + "value" + ], + "RadioGroup": [ + "value" + ], + "SwitchGroup": [ + "value" + ], + "Modal": [ + "open" + ] + } + }, "test": { "schema": { "$defs": { diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json index 8dc330a201..ede91f8860 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json @@ -1 +1 @@ -[{"name":"chat-example-1","schema":"chat","input":"Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }","checkpoints":[{"at":607,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["highlights","statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1214,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1821,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","valu":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ov2","ov3","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":13,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2428,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[],"isFoldable":null},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secLandmarks","secFood","secWhen","f","actionBtns","src1","src2"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3035,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":null,"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["lm1tagIcon","lm2","lm3","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3642,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["lm3body","lm3tag","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":33,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"lm3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["foodCards","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4856,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Sh"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":45,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5463,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"P"},"partial":true,"hasDynamicProps":false,"statementId":"sp2"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sp3","tabSummer","actionBtns","src1","src2"],"orphaned":[],"statementCount":51,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6070,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Sein"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["su2","su3","actionBtns","src1","src2"],"orphaned":[],"statementCount":55,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6677,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":true,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":true,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{}},"partial":true,"hasDynamicProps":false,"statementId":"btn2"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btn3","src1","src2"],"orphaned":[],"statementCount":60,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7277,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":false,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"springList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":false,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":false,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":false,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":false,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{"type":"continue_conversation","context":"Show me the best hotels in Paris"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn2"},{"type":"element","typeName":"Button","props":{"label":"Build a Paris Itinerary","action":{"type":"continue_conversation","context":"Build a 5-day Paris itinerary for me"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn3"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[{"title":"Paris Travel Guide 2025","sourceName":"Travel and Tour World","url":"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/"},{"title":"Best Things to Do in Paris 2026","sourceName":"Time Out Paris","url":"http://www.timeout.fr/paris/en/for-tourists"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-2","schema":"chat","input":"Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")","checkpoints":[{"at":510,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpi1icon","kpi1rhs","kpi2","kpi3","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi1lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1020,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3icon","kpi3rhs","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":13,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi3lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1530,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabGrowth","t","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2040,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["retentio","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2550,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":35,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3060,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tab","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3570,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Sta"]},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":47,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4080,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":null,"body":[]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["supportIcon","supportMetric","supportChart","supportList","cardMarketing","actionButtons"],"orphaned":[],"statementCount":51,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"supportHeader"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4590,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","rig":null}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sup2","sup3","cardMarketing","actionButtons"],"orphaned":[],"statementCount":58,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["marketingMetric","marketingChart","marketingList","actionButtons"],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":true,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":true,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":true,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":true,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Co"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["mkt3","actionButtons"],"orphaned":[],"statementCount":70,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6118,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":false,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":false,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":false,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":false,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Cost per Lead","right":"$48.20","rightVariant":"number"},{"left":"Top Channel","right":"Organic Search","rightVariant":"text"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Break Down by Channel","action":{"type":"continue_conversation","context":"Break down this month's revenue by acquisition channel"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnChannels"},{"type":"element","typeName":"Button","props":{"label":"Forecast Next Quarter","action":{"type":"continue_conversation","context":"Forecast revenue and active users for next quarter"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnForecast"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionButtons"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":74,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-3","schema":"chat","input":"Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)","checkpoints":[{"at":361,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas"},"partial":true,"hasDynamicProps":false,"statementId":"header"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","inspoCards","form"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":722,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["i","insp2","form"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"insp1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1083,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2","form"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1444,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":null,"size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2icon","form"],"orphaned":[],"statementCount":11,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1805,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btnSkip","fcDestination","fcDates","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":15,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2166,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Fo","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":19,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2527,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tr1","tr2","tr3","tr4","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2888,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["oc2","oc3","oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":29,"errors":[{"code":"missing-required","component":"OptionCard","path":"/title","message":"missing required field \"/title\" — signature: OptionCard(value*: string, title*: string, subtitle: string, topContent, disabled: boolean)","statementId":"oc1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":34,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fcNotes"],"orphaned":[],"statementCount":39,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"fcStay"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3971,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":null},"partial":true,"hasDynamicProps":false,"statementId":"ch3"}],"rules":{},"defaultValue":["hotel"]},"partial":true,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":true,"hasDynamicProps":false,"statementId":"fcStay"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ch4","fcNotes"],"orphaned":[],"statementCount":46,"errors":[{"code":"missing-required","component":"Icon","path":"/name","message":"missing required field \"/name\" — signature: Icon(name*: string, category: string)","statementId":"ch3icon"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4322,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":false,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":false,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":{"type":"element","typeName":"Icon","props":{"name":"home","category":"home"},"partial":false,"hasDynamicProps":false,"statementId":"ch3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch3"},{"type":"element","typeName":"ChipItem","props":{"value":"camping","label":"Camping / Glamping","icon":{"type":"element","typeName":"Icon","props":{"name":"tent","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"ch4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch4"}],"rules":{},"defaultValue":["hotel"]},"partial":false,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fcStay"},{"type":"element","typeName":"FormControl","props":{"label":"Special Requests or Notes","input":{"type":"element","typeName":"TextArea","props":{"name":"special-requests","placeholder":"e.g. vegetarian meals, wheelchair access, honeymoon surprise...","rows":4},"partial":false,"hasDynamicProps":false,"statementId":"notesArea"},"hint":"Any dietary needs, accessibility requirements, or specific interests?"},"partial":false,"hasDynamicProps":false,"statementId":"fcNotes"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":50,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-4","schema":"chat","input":"Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }","checkpoints":[{"at":218,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Ene"},"partial":true,"hasDynamicProps":false,"statementId":"header"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":436,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to w"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":654,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["v1body","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"v1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":872,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":null,"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v1icon","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1090,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":null,"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v2tag","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1308,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["CompositeCard","src1","src2"],"orphaned":[],"statementCount":14,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1526,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1icon","t1body","t1tags","t1btn","t2","src1","src2"],"orphaned":[],"statementCount":16,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t1h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1744,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Wa"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2","src1","src2"],"orphaned":[],"statementCount":20,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1962,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2icon","t2body","t2tags","t2btn","src1","src2"],"orphaned":[],"statementCount":22,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t2h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":[]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2btn","src1","src2"],"orphaned":[],"statementCount":25,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2398,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceN":null}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2615,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":false,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":false,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},{"title":"Sajan Re (Official Music Video)","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=COUSCnFazzc"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-5","schema":"chat","input":"Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")","checkpoints":[{"at":37,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":74,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["title","tbl","followUps"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":111,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":""},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tbl","followUps"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":148,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":185,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs","users","followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":222,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Pyth"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years","followUps"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":259,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["years","followUps"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":296,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":333,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu1"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":370,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me m"},"partial":true,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu2"],"orphaned":[],"statementCount":8,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":407,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["FollowUpItem"],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":442,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"},{"type":"element","typeName":"FollowUpItem","props":{"text":"Show me a JavaScript comparison"},"partial":false,"hasDynamicProps":false,"statementId":"fu2"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"basic","schema":"test","input":"root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Bu"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Button","path":"/label","message":"missing required field \"/label\" — signature: Button(label*: string, action, variant: \"primary\"|\"secondary\")","statementId":"b1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-required","schema":"test","input":"root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["B"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Button"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":51,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"null-required-with-default","schema":"test","input":"root = Card([t1])\nt1 = Text(null)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"required-default-fills","schema":"test","input":"root = Card([x])\nx = Tagged(1, true, \"x\", null)","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tag"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":null,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-component","schema":"test","input":"root = Card([Mystery(\"a\"), Text(\"b\")])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mys"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mystery"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"excess-args","schema":"test","input":"root = Card([Text(\"a\", \"m\", \"extra\", 4)])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":41,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"type-mismatch-scalar","schema":"test","input":"root = Card([Text(42)], 7)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/title","message":"field \"/title\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-mismatch","schema":"test","input":"root = Card([Text(\"a\", \"xl\"), Button(\"b\", null, \"tertiary\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Button"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"terti"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"tertiary"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/size","message":"field \"/size\" expects one of [\"s\", \"m\", \"l\"] but got \"xl\"","statementId":"root"},{"code":"type-mismatch","component":"Button","path":"/variant","message":"field \"/variant\" expects one of [\"primary\", \"secondary\"] but got \"tertiary\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-partial-deferred","schema":"test","input":"root = Card([Text(\"a\", \"x","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"integer-boolean-const","schema":"test","input":"root = Card([x])\nx = Tagged(1.5, \"yes\", \"y\", \"loud\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tagg"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":{"k":"Member","obj":{"k":"Num","v":1},"field":"?"},"tone":"neutral"},"partial":true,"hasDynamicProps":true,"statementId":"x"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"loud"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"loud"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"},{"code":"type-mismatch","component":"Tagged","path":"/kind","message":"field \"/kind\" expects one of [\"x\"] but got \"y\"","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"nested-object","schema":"test","input":"root = Card([c1, c2, c3])\nc1 = Chart([\"a\"], [1], {unit: \"kg\"})\nc2 = Chart([\"a\"], [1], {scale: 2})\nc3 = Chart([\"a\"], [1], {unit: 5, scale: \"big\"})","checkpoints":[{"at":13,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c1","c2","c3"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"un":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":65,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":78,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":91,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scal":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c2"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":104,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":117,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":130,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":143,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":145,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c3"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"},{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"array-items-pruned","schema":"test","input":"root = Card([Chart([\"a\", 2, \"c\"], [1, \"x\", 3])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"element-in-data-slot","schema":"test","input":"root = Card([Chart([Text(\"a\")], [1])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unresolved-and-orphaned","schema":"test","input":"root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a","miss"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":58,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cycle","schema":"test","input":"root = Card([a])\na = Card([b])\nb = Card([a])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"b"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"self-reference","schema":"test","input":"root = Card([root])","checkpoints":[{"at":2,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["r"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["roo"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"no-root-first-component","schema":"test","input":"x = 1\nmain = Card([Text(\"a\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["main"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"main"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"root-name-statement","schema":"test","input":"Card = Card([Text(\"named\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"Card"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"n"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"duplicate-ids","schema":"test","input":"root = Card([a])\na = Text(\"first\")\na = Text(\"second\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fir"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":53,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"only-prose","schema":"test","input":"Here is your UI, it will appear below.","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"whitespace","schema":"test","input":" \n\t \n","checkpoints":[{"at":1,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fences-and-prose","schema":"test","input":"Sure! Here it is:\n```openui\nroot = Card([a])\na = Text(\"fenced\")\n```\nAnything else?","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"f"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":82,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiple-fences","schema":"test","input":"```\nroot = Card([a])\n```\nand\n```\na = Text(\"second block\")\n```","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"secon"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second bloc"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unclosed-fence","schema":"test","input":"```openui\nroot = Card([a])\na = Text(\"str","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"str"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fence-in-string","schema":"test","input":"root = Card([a])\na = Text(\"use ``` to fence\")","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"u"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use `"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` t"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fe"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"comments","schema":"test","input":"root = Card([a]) // trailing\n# full line\na = Text(\"not // a comment # here\")\n// done","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not /"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a com"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment #"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"crlf","schema":"test","input":"root = Card([a])\r\na = Text(\"windows\")\r\n","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"wind"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"string-escapes","schema":"test","input":"root = Card([a, b, c, d])\na = Text(\"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83d\\ude00\")\nb = Text('single \\' quote \\n esc \\q')\nc = Text(\"bad \\x escape\")\nd = Text(\"emoji 😀 and é and 漢字\")","checkpoints":[{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nqu"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ uni"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":112,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' qu"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":128,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x"},"partial":true,"hasDynamicProps":false,"statementId":"c"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["d"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":160,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":176,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":true,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and"},"partial":true,"hasDynamicProps":false,"statementId":"d"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":187,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and é and 漢字"},"partial":false,"hasDynamicProps":false,"statementId":"d"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"emoji-outside-strings","schema":"test","input":"root = Card([a]) 😀\na = Text(\"ok\") ✅","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-string","schema":"test","input":"root = Card([a])\na = Text(\"streaming tex","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"s"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"strea"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming tex"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-escape","schema":"test","input":"root = Card([a])\na = Text(\"ends with \\","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with \\"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"numbers","schema":"test","input":"root = Card([Chart([\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"], [-3, 1.5, 1e3, 007, -0, 2.5e-3])])\n$x = 1e\n$y = 1E+2\n$z = 3.","checkpoints":[{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Chart"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,0]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,{"k":"Member","obj":{"k":"Num","v":2},"field":"?"},null]},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":81,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$x":null},"queryStatements":[],"mutationStatements":[]}},{"at":99,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$x":null,"$y":100},"queryStatements":[],"mutationStatements":[]}},{"at":106,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$x":null,"$y":100,"$z":{"k":"Member","obj":{"k":"Num","v":3},"field":"?"}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"operators","schema":"test","input":"$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])","checkpoints":[{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$a":1},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":""}}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"ye"},"else":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":88,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":92,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiline-ternary","schema":"test","input":"$on = true\nroot = Card([t])\nt = Text($on\n ? \"enabled\"\n : \"disabled\")","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"StateRef","n":"$on"}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"en"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabl"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabled"}}},"partial":false,"hasDynamicProps":true,"statementId":"t"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}}]},{"name":"member-index","schema":"test","input":"$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"row":null}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":""}]}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":null,"?":null}]}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key":null}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"row"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":139,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key x"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"builtins","schema":"test","input":"$items = [3, 1, 2]\nroot = Card([Text(\"\" + @Count($items)), Text(\"\" + @Sum($items)), Text(@Round(2.555, 2) + \"\")])\nbare = Count($items)","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3]},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Count"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Count"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Su"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Su"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Comp","name":"Round","args":[]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":134,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"actions","schema":"test","input":"$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))","checkpoints":[{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Card"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1","b2","b3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Ac","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Ph","n":"ToAssistant"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ToAssistant","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":126,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Ph","n":"Res"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Res","b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":162,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["But"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Action"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":198,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https:"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":215,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https://openui.com"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b3"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}}]},{"name":"each","schema":"test","input":"$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))","checkpoints":[{"at":10,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[]},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a"}]},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["f","f"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"ti":null,"?":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b"}]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["Each"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ph","n":"t"}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[],"mappedProps":{}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":110,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":113,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"query-mutation","schema":"test","input":"$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])","checkpoints":[{"at":19,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["users"],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":57,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"Null"}],["?",{"k":"Null"}]]},"defaultsAST":null,"refreshAST":null,"deps":["$q"],"complete":true}],"mutationStatements":[]}},{"at":76,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":null,"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":95,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["save"],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":114,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"Null"}],["?",{"k":"Null"}]]}}]}},{"at":133,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":152,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"le"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":171,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["B"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":190,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Actio"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":209,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Ph","n":"Run"}]}]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Run"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":221,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"users","refType":"query"}]}]}]}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}}]},{"name":"state-query","schema":"test","input":"$data = Query(\"get\", {})\nroot = Card([Text(\"x\")])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Qu","Qu"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":null},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":""},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":25,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}}]},{"name":"inline-query","schema":"test","input":"root = Card([Text(Query(\"get\", {}))])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Qu"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":37,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"assignment","schema":"test","input":"$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Inpu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"na"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"excess-args","component":"Input","path":"","message":"Input takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$valu"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$valu":null},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$value"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$value":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"object-key-order","schema":"test","input":"$o = {b: 1, 2: \"two\", a: 3, 1: \"one\", \"10\": 10}\nroot = Card([Text(\"x\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{}},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"tw","b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"two","b":1,"a":null}},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":null,"2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":null,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-commas","schema":"test","input":"root = Card([Text(\"a\") Text(\"b\"), Text(\"c\"),])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":46,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"lowercase-builtin-name","schema":"test","input":"root = Card([Text(@first([1]))])","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fi"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["first"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-tokens","schema":"test","input":"root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"combining-characters","schema":"test","input":"root = Card([Text(\"e\\u0301 cafe\\u0301\"), Text(\"한국어\"), Text(\"ok\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u03"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é caf"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u0301 cafe\\u030"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-call","schema":"test","input":"root = Card([a, b])\na = Text(\"one\")\nb = Button(\"tw","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","b"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Butto"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Button","props":{"label":"tw"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-object","schema":"test","input":"root = Card([Chart([\"a\"], [1], {unit: \"k","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":null,"?":null}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"k"}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"data-in-component-slot","schema":"test","input":"root = Card([Text(\"hi\"), { text: \"a\" }, \"b\", 3, [Text(\"x\")], true])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/5","message":"field \"/children/5\" expects Text | Button | Chart but got boolean","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":67,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/5","message":"field \"/children/5\" expects Text | Button | Chart but got boolean","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"data-in-component-slot-via-ref","schema":"test","input":"root = Card(items)\nitems = [{ text: \"a\" }]","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["item"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["items"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["items"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"hoisted-data-def","schema":"hoisted","input":"root = Tree({ label: \"a\" })","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Tr"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Tree","path":"/node","message":"missing required field \"/node\" — signature: Tree(node*: __schema0)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"l":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"labe":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":"a"}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":"a"}},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cloud-envelope","schema":"chat","input":"]]>openui:content?thesys=true\n```openui-lang\nroot = Card([h, t])\nh = CardHeader(\"Q3\", \"Revenue\")\nt = TextContent(\"Up 12%\")\n```\n]]>openui:end","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["h"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car","t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3"},"partial":true,"hasDynamicProps":false,"statementId":"h"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["TextCon"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":true,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":true,"hasDynamicProps":false,"statementId":"t"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":140,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}] +[{"name":"chat-example-1","schema":"chat","input":"Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }","checkpoints":[{"at":607,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["highlights","statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1214,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1821,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","valu":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ov2","ov3","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":13,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2428,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[],"isFoldable":null},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secLandmarks","secFood","secWhen","f","actionBtns","src1","src2"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3035,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":null,"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["lm1tagIcon","lm2","lm3","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3642,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["lm3body","lm3tag","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":33,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"lm3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["foodCards","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4856,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Sh"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":45,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5463,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"P"},"partial":true,"hasDynamicProps":false,"statementId":"sp2"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sp3","tabSummer","actionBtns","src1","src2"],"orphaned":[],"statementCount":51,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6070,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Sein"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["su2","su3","actionBtns","src1","src2"],"orphaned":[],"statementCount":55,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6677,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":true,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":true,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{}},"partial":true,"hasDynamicProps":false,"statementId":"btn2"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btn3","src1","src2"],"orphaned":[],"statementCount":60,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7277,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":false,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"springList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":false,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":false,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":false,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":false,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{"type":"continue_conversation","context":"Show me the best hotels in Paris"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn2"},{"type":"element","typeName":"Button","props":{"label":"Build a Paris Itinerary","action":{"type":"continue_conversation","context":"Build a 5-day Paris itinerary for me"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn3"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[{"title":"Paris Travel Guide 2025","sourceName":"Travel and Tour World","url":"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/"},{"title":"Best Things to Do in Paris 2026","sourceName":"Time Out Paris","url":"http://www.timeout.fr/paris/en/for-tourists"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-2","schema":"chat","input":"Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")","checkpoints":[{"at":510,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpi1icon","kpi1rhs","kpi2","kpi3","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi1lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1020,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3icon","kpi3rhs","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":13,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi3lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1530,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabGrowth","t","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2040,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["retentio","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2550,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":35,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3060,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tab","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3570,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Sta"]},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":47,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4080,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":null,"body":[]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["supportIcon","supportMetric","supportChart","supportList","cardMarketing","actionButtons"],"orphaned":[],"statementCount":51,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"supportHeader"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4590,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","rig":null}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sup2","sup3","cardMarketing","actionButtons"],"orphaned":[],"statementCount":58,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["marketingMetric","marketingChart","marketingList","actionButtons"],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":true,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":true,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":true,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":true,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Co"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["mkt3","actionButtons"],"orphaned":[],"statementCount":70,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6118,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":false,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":false,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":false,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":false,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Cost per Lead","right":"$48.20","rightVariant":"number"},{"left":"Top Channel","right":"Organic Search","rightVariant":"text"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Break Down by Channel","action":{"type":"continue_conversation","context":"Break down this month's revenue by acquisition channel"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnChannels"},{"type":"element","typeName":"Button","props":{"label":"Forecast Next Quarter","action":{"type":"continue_conversation","context":"Forecast revenue and active users for next quarter"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnForecast"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionButtons"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":74,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-3","schema":"chat","input":"Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)","checkpoints":[{"at":361,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas"},"partial":true,"hasDynamicProps":false,"statementId":"header"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","inspoCards","form"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":722,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["i","insp2","form"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"insp1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1083,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2","form"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1444,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":null,"size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2icon","form"],"orphaned":[],"statementCount":11,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1805,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btnSkip","fcDestination","fcDates","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":15,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2166,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Fo","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":19,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2527,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tr1","tr2","tr3","tr4","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2888,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["oc2","oc3","oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":29,"errors":[{"code":"missing-required","component":"OptionCard","path":"/title","message":"missing required field \"/title\" — signature: OptionCard(value*: string, title*: string, subtitle: string, topContent, disabled: boolean)","statementId":"oc1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":34,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fcNotes"],"orphaned":[],"statementCount":39,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"fcStay"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3971,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":null},"partial":true,"hasDynamicProps":false,"statementId":"ch3"}],"rules":{},"defaultValue":["hotel"]},"partial":true,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":true,"hasDynamicProps":false,"statementId":"fcStay"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ch4","fcNotes"],"orphaned":[],"statementCount":46,"errors":[{"code":"missing-required","component":"Icon","path":"/name","message":"missing required field \"/name\" — signature: Icon(name*: string, category: string)","statementId":"ch3icon"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4322,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":false,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":false,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":{"type":"element","typeName":"Icon","props":{"name":"home","category":"home"},"partial":false,"hasDynamicProps":false,"statementId":"ch3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch3"},{"type":"element","typeName":"ChipItem","props":{"value":"camping","label":"Camping / Glamping","icon":{"type":"element","typeName":"Icon","props":{"name":"tent","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"ch4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch4"}],"rules":{},"defaultValue":["hotel"]},"partial":false,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fcStay"},{"type":"element","typeName":"FormControl","props":{"label":"Special Requests or Notes","input":{"type":"element","typeName":"TextArea","props":{"name":"special-requests","placeholder":"e.g. vegetarian meals, wheelchair access, honeymoon surprise...","rows":4},"partial":false,"hasDynamicProps":false,"statementId":"notesArea"},"hint":"Any dietary needs, accessibility requirements, or specific interests?"},"partial":false,"hasDynamicProps":false,"statementId":"fcNotes"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":50,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-4","schema":"chat","input":"Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }","checkpoints":[{"at":218,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Ene"},"partial":true,"hasDynamicProps":false,"statementId":"header"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":436,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to w"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":654,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["v1body","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"v1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":872,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":null,"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v1icon","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1090,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":null,"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v2tag","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1308,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["CompositeCard","src1","src2"],"orphaned":[],"statementCount":14,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1526,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1icon","t1body","t1tags","t1btn","t2","src1","src2"],"orphaned":[],"statementCount":16,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t1h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1744,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Wa"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2","src1","src2"],"orphaned":[],"statementCount":20,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1962,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2icon","t2body","t2tags","t2btn","src1","src2"],"orphaned":[],"statementCount":22,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t2h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":[]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2btn","src1","src2"],"orphaned":[],"statementCount":25,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2398,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceN":null}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2615,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":false,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":false,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},{"title":"Sajan Re (Official Music Video)","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=COUSCnFazzc"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-5","schema":"chat","input":"Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")","checkpoints":[{"at":37,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":74,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["title","tbl","followUps"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":111,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":""},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tbl","followUps"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":148,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":185,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs","users","followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":222,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Pyth"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years","followUps"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":259,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["years","followUps"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":296,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":333,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu1"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":370,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me m"},"partial":true,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu2"],"orphaned":[],"statementCount":8,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":407,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["FollowUpItem"],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":442,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"},{"type":"element","typeName":"FollowUpItem","props":{"text":"Show me a JavaScript comparison"},"partial":false,"hasDynamicProps":false,"statementId":"fu2"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"openui-example-1","schema":"openui","input":"Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]","checkpoints":[{"at":28,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["titl"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["TextContent","tbl"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":112,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-hea"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tbl"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":140,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":168,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":196,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs","users","years"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":224,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","Java"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":252,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":280,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript","Go"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["years"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":308,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript","Go"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1,8.5,5.2]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":336,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript","Go"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1,8.5,5.2]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995,2012,2009]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"openui-example-2","schema":"openui","input":"Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])","checkpoints":[{"at":22,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["title"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["TextC","chart"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":88,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":""},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["chart"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":110,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["chart"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["labels","s1"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"BarChart","path":"/labels","message":"required field \"/labels\" cannot be null — signature: BarChart(labels*: array, series*: array, variant: \"grouped\"|\"stacked\", xLabel: string, yLabel: string, height: number)","statementId":"chart"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":154,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["labels","s1","s2"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"BarChart","path":"/labels","message":"required field \"/labels\" cannot be null — signature: BarChart(labels*: array, series*: array, variant: \"grouped\"|\"stacked\", xLabel: string, yLabel: string, height: number)","statementId":"chart"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":176,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[],"variant":"grouped"},"partial":true,"hasDynamicProps":false,"statementId":"chart"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["s1","s2"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":198,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[],"variant":"grouped"},"partial":true,"hasDynamicProps":false,"statementId":"chart"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["s2"],"orphaned":[],"statementCount":5,"errors":[{"code":"missing-required","component":"Series","path":"/values","message":"missing required field \"/values\" — signature: Series(category*: string, values*: array)","statementId":"s1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":220,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[{"type":"element","typeName":"Series","props":{"category":"Product A","values":[120,150,180]},"partial":false,"hasDynamicProps":false,"statementId":"s1"}],"variant":"grouped"},"partial":false,"hasDynamicProps":false,"statementId":"chart"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["s2"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":242,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[{"type":"element","typeName":"Series","props":{"category":"Product A","values":[120,150,180]},"partial":true,"hasDynamicProps":false,"statementId":"s1"}],"variant":"grouped"},"partial":true,"hasDynamicProps":false,"statementId":"chart"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[{"code":"missing-required","component":"Series","path":"/values","message":"missing required field \"/values\" — signature: Series(category*: string, values*: array)","statementId":"s2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":261,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[{"type":"element","typeName":"Series","props":{"category":"Product A","values":[120,150,180]},"partial":false,"hasDynamicProps":false,"statementId":"s1"},{"type":"element","typeName":"Series","props":{"category":"Product B","values":[90,110,140]},"partial":false,"hasDynamicProps":false,"statementId":"s2"}],"variant":"grouped"},"partial":false,"hasDynamicProps":false,"statementId":"chart"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"openui-example-3","schema":"openui","input":"Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])","checkpoints":[{"at":74,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","form"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":148,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","nameFi"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":222,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","emailField","countryField","msgField"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"nameField"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":296,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btns","emailField","countryField","msgField"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":370,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","countryField","msgField"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":444,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","Sel","msgField"],"orphaned":[],"statementCount":6,"errors":[{"code":"null-required","component":"FormControl","path":"/input","message":"required field \"/input\" cannot be null — signature: FormControl(label*: string, input*, hint: string)","statementId":"countryField"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":518,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btns","countryOpts","F"],"orphaned":[],"statementCount":7,"errors":[{"code":"null-required","component":"Select","path":"/items","message":"required field \"/items\" cannot be null — signature: Select(name*: string, items*: array, placeholder: string, rules: object, value: string, size: \"small\"|\"medium\"|\"large\")","statementId":"countryField"},{"code":"null-required","component":"FormControl","path":"/input","message":"required field \"/input\" cannot be null — signature: FormControl(label*: string, input*, hint: string)","statementId":"countryField"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":592,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","countryOpts"],"orphaned":[],"statementCount":7,"errors":[{"code":"null-required","component":"Select","path":"/items","message":"required field \"/items\" cannot be null — signature: Select(name*: string, items*: array, placeholder: string, rules: object, value: string, size: \"small\"|\"medium\"|\"large\")","statementId":"countryField"},{"code":"null-required","component":"FormControl","path":"/input","message":"required field \"/input\" cannot be null — signature: FormControl(label*: string, input*, hint: string)","statementId":"countryField"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":666,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns"],"orphaned":[],"statementCount":8,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":740,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btns"],"orphaned":[],"statementCount":8,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":814,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Form","props":{"name":"contact","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Submit","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Submit"}]}]}]},"variant":"primary"},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"btns"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Name","input":{"type":"element","typeName":"Input","props":{"name":"name","placeholder":"Your name","type":"text","rules":{"required":true,"minLength":2}},"partial":true,"hasDynamicProps":false}},"partial":true,"hasDynamicProps":false,"statementId":"nameField"},{"type":"element","typeName":"FormControl","props":{"label":"Email","input":{"type":"element","typeName":"Input","props":{"name":"email","placeholder":"you@example.com","type":"email","rules":{"required":true,"email":true}},"partial":true,"hasDynamicProps":false}},"partial":true,"hasDynamicProps":false,"statementId":"emailField"},{"type":"element","typeName":"FormControl","props":{"label":"Country","input":{"type":"element","typeName":"Select","props":{"name":"country","items":[{"type":"element","typeName":"SelectItem","props":{"value":"us","label":"United States"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"uk","label":"United Kingdom"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"de","label":"Germany"},"partial":true,"hasDynamicProps":false}],"placeholder":"Select...","rules":{"required":true}},"partial":true,"hasDynamicProps":false}},"partial":true,"hasDynamicProps":false,"statementId":"countryField"},{"type":"element","typeName":"FormControl","props":{"label":"Message","input":{"type":"element","typeName":"TextArea","props":{"name":"message","placeholder":"Tell us more...","rows":4,"rules":{"required":true,"minLength":10}},"partial":true,"hasDynamicProps":false}},"partial":true,"hasDynamicProps":false,"statementId":"msgField"}]},"partial":true,"hasDynamicProps":true,"statementId":"form"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Bu"],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":877,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Form","props":{"name":"contact","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Submit","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Submit"}]}]}]},"variant":"primary"},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Cancel","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Cancel"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"btns"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Name","input":{"type":"element","typeName":"Input","props":{"name":"name","placeholder":"Your name","type":"text","rules":{"required":true,"minLength":2}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"nameField"},{"type":"element","typeName":"FormControl","props":{"label":"Email","input":{"type":"element","typeName":"Input","props":{"name":"email","placeholder":"you@example.com","type":"email","rules":{"required":true,"email":true}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"emailField"},{"type":"element","typeName":"FormControl","props":{"label":"Country","input":{"type":"element","typeName":"Select","props":{"name":"country","items":[{"type":"element","typeName":"SelectItem","props":{"value":"us","label":"United States"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"uk","label":"United Kingdom"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"de","label":"Germany"},"partial":false,"hasDynamicProps":false}],"placeholder":"Select...","rules":{"required":true}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"countryField"},{"type":"element","typeName":"FormControl","props":{"label":"Message","input":{"type":"element","typeName":"TextArea","props":{"name":"message","placeholder":"Tell us more...","rows":4,"rules":{"required":true,"minLength":10}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"msgField"}]},"partial":false,"hasDynamicProps":true,"statementId":"form"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"openui-example-4","schema":"openui","input":"Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]","checkpoints":[{"at":43,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":86,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabs"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"TextContent","path":"/text","message":"missing required field \"/text\" — signature: TextContent(text*: string, size: \"small\"|\"default\"|\"large\"|\"small-heavy\"|\"large-heavy\")","statementId":"title"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":129,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Tabs","path":"/items","message":"missing required field \"/items\" — signature: Tabs(items*: array)","statementId":"tabs"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":172,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabVue"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"TabItem","path":"/trigger","message":"missing required field \"/trigger\" — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabReact"},{"code":"missing-required","component":"TabItem","path":"/content","message":"missing required field \"/content\" — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabReact"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":215,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["reactContent","TabIte"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabReact"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":258,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["reactContent","vueContent"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabReact"},{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabVue"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":301,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta fo"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["vueContent"],"orphaned":[],"statementCount":6,"errors":[{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabVue"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":344,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["vueContent"],"orphaned":[],"statementCount":6,"errors":[{"code":"missing-required","component":"Callout","path":"/description","message":"missing required field \"/description\" — signature: Callout(variant*: \"info\"|\"warning\"|\"error\"|\"success\"|\"neutral\", title*: string, description*: string, visible: boolean)","statementId":"reactContent"},{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabVue"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":387,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":430,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[{"type":"element","typeName":"TextContent","props":{"text":"Vue is a progressive framework b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":473,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[{"type":"element","typeName":"TextContent","props":{"text":"Vue is a progressive framework by Evan You."},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"success","title":"Tip","description":"V"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":507,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[{"type":"element","typeName":"TextContent","props":{"text":"Vue is a progressive framework by Evan You."},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"success","title":"Tip","description":"Vue has a gentle learning curve."},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"openui-example-5","schema":"openui","input":"Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")","checkpoints":[{"at":164,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpiBlock","productsHeader","productCards"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":328,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi1icon","kpi1rhs","kpi2","kpi3","productsHeader","productCards"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi1lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":492,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3","productsHeader","productCards"],"orphaned":[],"statementCount":8,"errors":[{"code":"missing-required","component":"SnippetCardItem","path":"/lhs","message":"missing required field \"/lhs\" — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":656,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":null},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpi2rhs","kpi3","productsHeader","productCards"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":820,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3icon","kpi3rhs","productsHeader","productCards"],"orphaned":[],"statementCount":13,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi3lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":984,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Pro"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["productCards"],"orphaned":[],"statementCount":16,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1148,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":null,"body":[],"footer":null},"partial":true,"hasDynamicProps":false,"statementId":"p1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"productCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["p1icon","p1body","p1footer","p2"],"orphaned":[],"statementCount":19,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"p1header"},{"code":"missing-required","component":"IconText","path":"/title","message":"missing required field \"/title\" — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"p1header"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1312,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":true,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month"},"partial":true,"hasDynamicProps":false,"statementId":"p1body"}],"footer":null},"partial":true,"hasDynamicProps":false,"statementId":"p1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"productCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["p1footer","p2"],"orphaned":[],"statementCount":21,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1476,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":true,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":true,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":true,"hasDynamicProps":true,"statementId":"p1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["p2"],"orphaned":[],"statementCount":23,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1640,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":true,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":true,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Pro"}]}]}]},"variant":"secondary"},"partial":true,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":true,"hasDynamicProps":true,"statementId":"p1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-mini","header":null,"body":[],"footer":null},"partial":true,"hasDynamicProps":false,"statementId":"p2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["p2icon","p2body","p2footer"],"orphaned":[],"statementCount":25,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"p2header"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1804,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":false,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":false,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Pro"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":false,"hasDynamicProps":true,"statementId":"p1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-mini","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"box","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p2icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Mini","subtitle":"New arrival","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p2header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"980 units","subtext":"Sold this month","trend":{"direction":"up","value":4}},"partial":false,"hasDynamicProps":false,"statementId":"p2body"}],"footer":null},"partial":false,"hasDynamicProps":false,"statementId":"p2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["p2footer"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1962,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":false,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":false,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Pro"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":false,"hasDynamicProps":true,"statementId":"p1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-mini","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"box","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p2icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Mini","subtitle":"New arrival","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p2header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"980 units","subtext":"Sold this month","trend":{"direction":"up","value":4}},"partial":false,"hasDynamicProps":false,"statementId":"p2body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$14.00","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Mini"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true,"statementId":"p2btn"}}},"partial":false,"hasDynamicProps":true,"statementId":"p2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":29,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"openui-example-6","schema":"openui","input":"Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])","checkpoints":[{"at":142,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Te"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["editTable","formHeader","prefsForm"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":284,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text"}],"data":[]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["colRole","colStart","row1","row2","formHeader","prefsForm"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":426,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"en"}]}],"data":[]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["roleDesign","colStart","row1","row2","formHeader","prefsForm"],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":568,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Da"}],"data":[]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["row1","row2","formHeader","prefsForm"],"orphaned":[],"statementCount":8,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":710,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":false,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":false,"hasDynamicProps":false,"statementId":"editTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["formHeader","prefsForm"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":852,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","fc2"],"orphaned":[],"statementCount":13,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"fc1"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":994,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","style2","fc2"],"orphaned":[],"statementCount":15,"errors":[{"code":"missing-required","component":"OptionCard","path":"/title","message":"missing required field \"/title\" — signature: OptionCard(value*: string, title*: string, subtitle: string, topContent, disabled: boolean)","statementId":"style1"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1136,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","fc2"],"orphaned":[],"statementCount":17,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1278,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":false,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":false,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":false,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["formButtons","toolChips"],"orphaned":[],"statementCount":19,"errors":[{"code":"null-required","component":"FormControl","path":"/input","message":"required field \"/input\" cannot be null — signature: FormControl(label*: string, input*, hint: string)","statementId":"fc2"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1420,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","tool2","tool3"],"orphaned":[],"statementCount":22,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1562,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","tool3"],"orphaned":[],"statementCount":25,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1699,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":false,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":false,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":false,"hasDynamicProps":false,"statementId":"formHeader"},{"type":"element","typeName":"Form","props":{"name":"prefs","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Save preferences"}]}]}]},"variant":"primary"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Working Style","input":{"type":"element","typeName":"OptionCards","props":{"name":"style","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"focused","title":"Deep Focus","subtitle":"Long uninterrupted blocks","topContent":{"type":"element","typeName":"Icon","props":{"name":"target","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"style1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"style1"},{"type":"element","typeName":"OptionCard","props":{"value":"collab","title":"Collaborative","subtitle":"Frequent pairing and syncs","topContent":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"style2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"style2"}]},"partial":false,"hasDynamicProps":false,"statementId":"styleCards"},"hint":"Pick the one that fits best"},"partial":false,"hasDynamicProps":false,"statementId":"fc1"},{"type":"element","typeName":"FormControl","props":{"label":"Tools","input":{"type":"element","typeName":"Chips","props":{"name":"tools","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"figma","label":"Figma","icon":{"type":"element","typeName":"Icon","props":{"name":"figma","category":"design"},"partial":false,"hasDynamicProps":false,"statementId":"tool1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool1"},{"type":"element","typeName":"ChipItem","props":{"value":"slack","label":"Slack","icon":{"type":"element","typeName":"Icon","props":{"name":"message-square","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"tool2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool2"},{"type":"element","typeName":"ChipItem","props":{"value":"notion","label":"Notion","icon":{"type":"element","typeName":"Icon","props":{"name":"notebook","category":"text"},"partial":false,"hasDynamicProps":false,"statementId":"tool3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool3"}]},"partial":false,"hasDynamicProps":false,"statementId":"toolChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fc2"}]},"partial":false,"hasDynamicProps":true,"statementId":"prefsForm"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"basic","schema":"test","input":"root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Bu"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Button","path":"/label","message":"missing required field \"/label\" — signature: Button(label*: string, action, variant: \"primary\"|\"secondary\")","statementId":"b1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-required","schema":"test","input":"root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["B"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Button"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":51,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"null-required-with-default","schema":"test","input":"root = Card([t1])\nt1 = Text(null)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"required-default-fills","schema":"test","input":"root = Card([x])\nx = Tagged(1, true, \"x\", null)","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tag"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":null,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-component","schema":"test","input":"root = Card([Mystery(\"a\"), Text(\"b\")])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mys"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mystery"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"excess-args","schema":"test","input":"root = Card([Text(\"a\", \"m\", \"extra\", 4)])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":41,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"type-mismatch-scalar","schema":"test","input":"root = Card([Text(42)], 7)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/title","message":"field \"/title\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-mismatch","schema":"test","input":"root = Card([Text(\"a\", \"xl\"), Button(\"b\", null, \"tertiary\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Button"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"terti"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"tertiary"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/size","message":"field \"/size\" expects one of [\"s\", \"m\", \"l\"] but got \"xl\"","statementId":"root"},{"code":"type-mismatch","component":"Button","path":"/variant","message":"field \"/variant\" expects one of [\"primary\", \"secondary\"] but got \"tertiary\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-partial-deferred","schema":"test","input":"root = Card([Text(\"a\", \"x","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"integer-boolean-const","schema":"test","input":"root = Card([x])\nx = Tagged(1.5, \"yes\", \"y\", \"loud\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tagg"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":{"k":"Member","obj":{"k":"Num","v":1},"field":"?"},"tone":"neutral"},"partial":true,"hasDynamicProps":true,"statementId":"x"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"loud"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"loud"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"},{"code":"type-mismatch","component":"Tagged","path":"/kind","message":"field \"/kind\" expects one of [\"x\"] but got \"y\"","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"nested-object","schema":"test","input":"root = Card([c1, c2, c3])\nc1 = Chart([\"a\"], [1], {unit: \"kg\"})\nc2 = Chart([\"a\"], [1], {scale: 2})\nc3 = Chart([\"a\"], [1], {unit: 5, scale: \"big\"})","checkpoints":[{"at":13,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c1","c2","c3"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"un":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":65,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":78,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":91,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scal":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c2"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":104,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":117,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":130,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":143,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":145,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c3"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"},{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"array-items-pruned","schema":"test","input":"root = Card([Chart([\"a\", 2, \"c\"], [1, \"x\", 3])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"element-in-data-slot","schema":"test","input":"root = Card([Chart([Text(\"a\")], [1])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unresolved-and-orphaned","schema":"test","input":"root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a","miss"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":58,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cycle","schema":"test","input":"root = Card([a])\na = Card([b])\nb = Card([a])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"b"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"self-reference","schema":"test","input":"root = Card([root])","checkpoints":[{"at":2,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["r"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["roo"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"no-root-first-component","schema":"test","input":"x = 1\nmain = Card([Text(\"a\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["main"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"main"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"root-name-statement","schema":"test","input":"Card = Card([Text(\"named\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"Card"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"n"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"duplicate-ids","schema":"test","input":"root = Card([a])\na = Text(\"first\")\na = Text(\"second\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fir"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":53,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"only-prose","schema":"test","input":"Here is your UI, it will appear below.","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"whitespace","schema":"test","input":" \n\t \n","checkpoints":[{"at":1,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fences-and-prose","schema":"test","input":"Sure! Here it is:\n```openui\nroot = Card([a])\na = Text(\"fenced\")\n```\nAnything else?","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"f"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":82,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiple-fences","schema":"test","input":"```\nroot = Card([a])\n```\nand\n```\na = Text(\"second block\")\n```","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"secon"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second bloc"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unclosed-fence","schema":"test","input":"```openui\nroot = Card([a])\na = Text(\"str","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"str"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fence-in-string","schema":"test","input":"root = Card([a])\na = Text(\"use ``` to fence\")","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"u"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use `"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` t"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fe"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"comments","schema":"test","input":"root = Card([a]) // trailing\n# full line\na = Text(\"not // a comment # here\")\n// done","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not /"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a com"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment #"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"crlf","schema":"test","input":"root = Card([a])\r\na = Text(\"windows\")\r\n","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"wind"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"string-escapes","schema":"test","input":"root = Card([a, b, c, d])\na = Text(\"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83d\\ude00\")\nb = Text('single \\' quote \\n esc \\q')\nc = Text(\"bad \\x escape\")\nd = Text(\"emoji 😀 and é and 漢字\")","checkpoints":[{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nqu"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ uni"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":112,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' qu"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":128,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x"},"partial":true,"hasDynamicProps":false,"statementId":"c"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["d"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":160,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":176,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":true,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and"},"partial":true,"hasDynamicProps":false,"statementId":"d"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":187,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and é and 漢字"},"partial":false,"hasDynamicProps":false,"statementId":"d"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"emoji-outside-strings","schema":"test","input":"root = Card([a]) 😀\na = Text(\"ok\") ✅","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-string","schema":"test","input":"root = Card([a])\na = Text(\"streaming tex","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"s"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"strea"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming tex"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-escape","schema":"test","input":"root = Card([a])\na = Text(\"ends with \\","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with \\"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"numbers","schema":"test","input":"root = Card([Chart([\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"], [-3, 1.5, 1e3, 007, -0, 2.5e-3])])\n$x = 1e\n$y = 1E+2\n$z = 3.","checkpoints":[{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Chart"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,0]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,{"k":"Member","obj":{"k":"Num","v":2},"field":"?"},null]},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":81,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$x":null},"queryStatements":[],"mutationStatements":[]}},{"at":99,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$x":null,"$y":100},"queryStatements":[],"mutationStatements":[]}},{"at":106,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$x":null,"$y":100,"$z":{"k":"Member","obj":{"k":"Num","v":3},"field":"?"}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"operators","schema":"test","input":"$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])","checkpoints":[{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$a":1},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":""}}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"ye"},"else":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":88,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":92,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiline-ternary","schema":"test","input":"$on = true\nroot = Card([t])\nt = Text($on\n ? \"enabled\"\n : \"disabled\")","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"StateRef","n":"$on"}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"en"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabl"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabled"}}},"partial":false,"hasDynamicProps":true,"statementId":"t"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}}]},{"name":"member-index","schema":"test","input":"$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"row":null}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":""}]}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":null,"?":null}]}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key":null}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"row"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":139,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key x"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"builtins","schema":"test","input":"$items = [3, 1, 2]\nroot = Card([Text(\"\" + @Count($items)), Text(\"\" + @Sum($items)), Text(@Round(2.555, 2) + \"\")])\nbare = Count($items)","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3]},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Count"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Count"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Su"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Su"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Comp","name":"Round","args":[]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":134,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"actions","schema":"test","input":"$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))","checkpoints":[{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Card"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1","b2","b3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Ac","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Ph","n":"ToAssistant"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ToAssistant","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":126,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Ph","n":"Res"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Res","b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":162,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["But"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Action"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":198,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https:"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":215,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https://openui.com"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b3"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}}]},{"name":"each","schema":"test","input":"$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))","checkpoints":[{"at":10,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[]},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a"}]},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["f","f"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"ti":null,"?":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b"}]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["Each"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ph","n":"t"}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[],"mappedProps":{}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":110,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":113,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"query-mutation","schema":"test","input":"$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])","checkpoints":[{"at":19,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["users"],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":57,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"Null"}],["?",{"k":"Null"}]]},"defaultsAST":null,"refreshAST":null,"deps":["$q"],"complete":true}],"mutationStatements":[]}},{"at":76,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":null,"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":95,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["save"],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":114,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"Null"}],["?",{"k":"Null"}]]}}]}},{"at":133,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":152,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"le"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":171,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["B"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":190,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Actio"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":209,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Ph","n":"Run"}]}]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Run"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":221,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"users","refType":"query"}]}]}]}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}}]},{"name":"state-query","schema":"test","input":"$data = Query(\"get\", {})\nroot = Card([Text(\"x\")])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Qu","Qu"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":null},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":""},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":25,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}}]},{"name":"inline-query","schema":"test","input":"root = Card([Text(Query(\"get\", {}))])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Qu"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":37,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"assignment","schema":"test","input":"$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Inpu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"na"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"excess-args","component":"Input","path":"","message":"Input takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$valu"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$valu":null},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$value"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$value":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"object-key-order","schema":"test","input":"$o = {b: 1, 2: \"two\", a: 3, 1: \"one\", \"10\": 10}\nroot = Card([Text(\"x\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{}},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"tw","b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"two","b":1,"a":null}},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":null,"2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":null,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-commas","schema":"test","input":"root = Card([Text(\"a\") Text(\"b\"), Text(\"c\"),])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":46,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"lowercase-builtin-name","schema":"test","input":"root = Card([Text(@first([1]))])","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fi"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["first"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-tokens","schema":"test","input":"root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"combining-characters","schema":"test","input":"root = Card([Text(\"e\\u0301 cafe\\u0301\"), Text(\"한국어\"), Text(\"ok\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u03"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é caf"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u0301 cafe\\u030"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-call","schema":"test","input":"root = Card([a, b])\na = Text(\"one\")\nb = Button(\"tw","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","b"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Butto"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Button","props":{"label":"tw"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-object","schema":"test","input":"root = Card([Chart([\"a\"], [1], {unit: \"k","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":null,"?":null}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"k"}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"data-in-component-slot","schema":"test","input":"root = Card([Text(\"hi\"), { text: \"a\" }, \"b\", 3, [Text(\"x\")], true])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/5","message":"field \"/children/5\" expects Text | Button | Chart but got boolean","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":67,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/5","message":"field \"/children/5\" expects Text | Button | Chart but got boolean","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"data-in-component-slot-via-ref","schema":"test","input":"root = Card(items)\nitems = [{ text: \"a\" }]","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["item"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["items"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["items"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"hoisted-data-def","schema":"hoisted","input":"root = Tree({ label: \"a\" })","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Tr"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Tree","path":"/node","message":"missing required field \"/node\" — signature: Tree(node*: __schema0)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"l":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"labe":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":"a"}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":"a"}},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cloud-envelope","schema":"chat","input":"]]>openui:content?thesys=true\n```openui-lang\nroot = Card([h, t])\nh = CardHeader(\"Q3\", \"Revenue\")\nt = TextContent(\"Up 12%\")\n```\n]]>openui:end","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["h"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car","t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3"},"partial":true,"hasDynamicProps":false,"statementId":"h"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["TextCon"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":true,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":true,"hasDynamicProps":false,"statementId":"t"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":140,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}] diff --git a/packages/swift-lang/Tests/OpenUILangTests/LibraryComponentsTests.swift b/packages/swift-lang/Tests/OpenUILangTests/LibraryComponentsTests.swift new file mode 100644 index 0000000000..7010e2933e --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/LibraryComponentsTests.swift @@ -0,0 +1,107 @@ +import Testing + +@testable import OpenUILang + +/// The component schemas must match react-ui's Zod schemas, for both +/// openuiChatLibrary (`ChatComponents`) and openuiLibrary (`OpenUIComponents`), +/// so one backend prompt drives both the web and native renderers. +@Suite struct LibraryComponentsTests { + /// One of react-ui's libraries: its fixture key, root and Swift schemas. + struct Subject { + let key: String + let root: String + let all: [ComponentSchema] + let groups: [ComponentGroup] + let promptOptions: PromptOptions + + var tsDefs: OpenUIValue { Fixtures.schemas[key]["schema"]["$defs"] } + var tsSpec: OpenUIValue { Fixtures.load("\(key)-spec") } + var library: Library { + Library( + components: all.map { ComponentDefinition($0, content: ()) }, root: root, + componentGroups: groups) + } + } + + static func subject(_ key: String) -> Subject { + key == "chat" + ? Subject( + key: "chat", root: "Card", all: ChatComponents.all, groups: ChatComponents.groups, + promptOptions: ChatComponents.promptOptions) + : Subject( + key: "openui", root: "Stack", all: OpenUIComponents.all, groups: OpenUIComponents.groups, + promptOptions: OpenUIComponents.promptOptions) + } + + static let libraries = ["chat", "openui"] + static let components: [(String, String)] = libraries.flatMap { key in + subject(key).all.map { (key, $0.name) } + } + + @Test(arguments: components) + func matchesReactUI(_ key: String, _ name: String) { + let subject = Self.subject(key) + let schema = subject.all.first { $0.name == name }! + let expected = subject.tsDefs[name] + let diff = firstDifference(normalized(schema.jsonSchema), normalized(expected)) + #expect(diff == nil, "\(key) \(name): \(diff ?? "")") + // Property order is positional-argument order, so it must match exactly. + #expect( + schema.jsonSchema["properties"].objectValue?.keys == expected["properties"].objectValue?.keys) + #expect(schema.signature == subject.tsSpec["components"][name]["signature"].stringValue) + } + + @Test(arguments: libraries) + func coversEveryComponentInLibraryOrder(_ key: String) { + let subject = Self.subject(key) + #expect(subject.all.map(\.name) == subject.tsSpec["components"].objectValue?.keys) + } + + @Test(arguments: libraries) + func libraryJSONSchemaMatchesByteForByte(_ key: String) { + // Key order included: top-level properties follow library order, $defs + // follow Zod's depth-first discovery order. + let schema = JSON.stringify(Self.subject(key).library.toJSONSchema()) + let expected = JSON.stringify(Fixtures.schemas[key]["schema"]) + #expect(schema == expected, "\(firstLineDifference(schema, expected) ?? "")") + } + + @Test(arguments: libraries) + func bindingsMatchReactiveProps(_ key: String) { + let reactive = Fixtures.schemas[key]["reactive"].objectValue ?? OpenUIObject() + for schema in Self.subject(key).all { + let expected = (reactive[schema.name]?.arrayValue ?? []).compactMap(\.stringValue) + #expect(schema.props.filter(\.isBinding).map(\.name) == expected, "\(key) \(schema.name)") + } + } + + @Test(arguments: libraries) + func groupsMatchReactUI(_ key: String) { + let subject = Self.subject(key) + let expected = (subject.tsSpec["componentGroups"].arrayValue ?? []).map { group in + ComponentGroup( + name: group["name"].stringValue ?? "", + components: (group["components"].arrayValue ?? []).compactMap(\.stringValue), + notes: group["notes"].arrayValue?.compactMap(\.stringValue)) + } + #expect(subject.groups == expected) + } + + @Test(arguments: libraries) + func promptWithItsOptionsMatchesLangCore(_ key: String) { + // What react-ui apps send: the library with its prompt options. + let subject = Self.subject(key) + let fixture = FixtureCase.all("prompts").first { $0.name == "\(key)-options" }! + let prompt = subject.library.prompt(subject.promptOptions) + let expected = fixture.value["expected"].stringValue! + #expect(prompt == expected, "\(firstLineDifference(prompt, expected) ?? "")") + } + + @Test(arguments: libraries) + func promptMatchesLangCore(_ key: String) { + let fixture = FixtureCase.all("prompts").first { $0.name == "\(key)-default" }! + let prompt = Self.subject(key).library.prompt() + let expected = fixture.value["expected"].stringValue! + #expect(prompt == expected, "\(firstLineDifference(prompt, expected) ?? "")") + } +} diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/openui-examples.json b/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/openui-examples.json new file mode 100644 index 0000000000..8afad79c5a --- /dev/null +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/openui-examples.json @@ -0,0 +1,26 @@ +[ + { + "name": "openui-example-1", + "input": "Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]" + }, + { + "name": "openui-example-2", + "input": "Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])" + }, + { + "name": "openui-example-3", + "input": "Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])" + }, + { + "name": "openui-example-4", + "input": "Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]" + }, + { + "name": "openui-example-5", + "input": "Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")" + }, + { + "name": "openui-example-6", + "input": "Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])" + } +] diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 32ffe30204..9dd9ec50bb 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -164,6 +164,101 @@ import Testing #expect(host.fittingSize.height > 120, "\(name) rendered \(host.fittingSize)") } + nonisolated static let openUIExamples: [(name: String, input: String)] = { + let url = Bundle.module.url( + forResource: "openui-examples", withExtension: "json", subdirectory: "Fixtures")! + let json = try! JSON.parse(String(contentsOf: url, encoding: .utf8)) + return (json.arrayValue ?? []).map { ($0["name"].stringValue!, $0["input"].stringValue!) } + }() + + /// The same for react-ui's general library, `openuiLibrary`, whose + /// examples start from a Stack. + @Test(arguments: openUIExamples.map(\.name)) + func rendersOpenUIExample(_ name: String) { + let input = Self.openUIExamples.first { $0.name == name }!.input + var errors: [OpenUIError] = [] + let host = NSHostingView( + rootView: OpenUIRenderer( + response: input, library: OpenUILibrary.library, onError: { errors = $0 } + ) + .frame(width: 420)) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 420, height: 600), styleMask: [.borderless], + backing: .buffered, defer: false) + window.contentView = host + RunLoop.main.run(until: Date().addingTimeInterval(0.3)) + #expect(host.fittingSize.height > 100, "\(name) rendered \(host.fittingSize)") + // Only the example's prose heading may fail to parse. + #expect(errors.allSatisfy { $0.jsonRepresentation["source"] == "parser" }, "\(errors)") + } + + /// A closed Modal takes no room in a Stack, gap included, as in react-ui + /// where it renders nothing. + @Test func closedModalTakesNoRoom() { + func height(_ input: String) -> CGFloat { + let host = NSHostingView( + rootView: OpenUIRenderer(response: input, library: OpenUILibrary.library) + .frame(width: 420)) + RunLoop.main.run(until: Date().addingTimeInterval(0.2)) + return host.fittingSize.height + } + let alone = height(#"root = Stack([TextContent("Profile"), TextContent("Name")])"#) + let withModal = height( + """ + $open = false + root = Stack([TextContent("Profile"), modal, TextContent("Name")]) + modal = Modal("Edit", $open, [TextContent("Hi")]) + """) + #expect(alone > 0) + #expect(withModal == alone) + } + + /// openuiLibrary's Modal opens from its `open` binding, and closing the + /// sheet (its X, Escape, a swipe) writes false back. + @Test func modalFollowsItsOpenBinding() { + final class Box { var state = OpenUIObject() } + let box = Box() + let input = """ + $open = true + root = Stack([title, modal]) + title = TextContent("Profile") + modal = Modal("Edit profile", $open, [TextContent("Change your name")]) + """ + let host = NSHostingView( + rootView: OpenUIRenderer( + response: input, library: OpenUILibrary.library, onStateUpdate: { box.state = $0 } + ) + .frame(width: 420, height: 300)) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 420, height: 300), styleMask: [.titled], + backing: .buffered, defer: false) + window.isReleasedWhenClosed = false + window.contentView = host + window.orderFrontRegardless() + defer { window.close() } + // Poll rather than wait a fixed time: CI machines are slower. + func wait(until done: () -> Bool) { + for _ in 0..<50 where !done() { RunLoop.main.run(until: Date().addingTimeInterval(0.1)) } + } + wait { window.attachedSheet != nil } + guard let sheet = window.attachedSheet else { + Issue.record("no sheet for $open = true") + return + } + // Escape, which the sheet's close button answers to. + sheet.makeKey() + for type in [NSEvent.EventType.keyDown, .keyUp] { + let escape = NSEvent.keyEvent( + with: type, location: .zero, modifierFlags: [], timestamp: 0, + windowNumber: sheet.windowNumber, context: nil, characters: "\u{1b}", + charactersIgnoringModifiers: "\u{1b}", isARepeat: false, keyCode: 53)! + sheet.sendEvent(escape) + } + wait { window.attachedSheet == nil && box.state["$open"] == false } + #expect(window.attachedSheet == nil) + #expect(box.state["$open"] == false) + } + /// The bug vishxrad hit in the Angular port: an input recreated on every /// update loses focus mid-typing. The AppKit text field behind the SwiftUI /// input must be the same object across streamed updates and typing. @@ -590,3 +685,54 @@ let globalTestLibrary = SwiftUILibrary( == CGPoint(x: 8, y: -90)) } } + +/// The flex layout behind openuiLibrary's Stack and Card, against what CSS +/// flexbox does with react-ui's styles. +@Suite struct FlexLayoutTests { + typealias Item = FlexLayout.Item + + @Test func growingItemsShareTheFreeSpace() { + // Two cards (flex: 1, basis 0) and a 100pt button in 400pt with 12pt gaps. + let items = [ + Item(basis: 0, flexible: true), Item(basis: 100, flexible: false), + Item(basis: 0, flexible: true), + ] + let (widths, offsets) = FlexLayout.distribute(items, width: 400, gap: 12, justify: nil) + #expect(widths == [138, 100, 138]) + #expect(offsets == [0, 150, 262]) + } + + @Test func justifySpreadsSpaceWhenNothingGrows() { + let items = [Item(basis: 100, flexible: false), Item(basis: 100, flexible: false)] + func offsets(_ justify: String?) -> [CGFloat] { + FlexLayout.distribute(items, width: 300, gap: 0, justify: justify).offsets + } + #expect(offsets(nil) == [0, 100]) + #expect(offsets("center") == [50, 150]) + #expect(offsets("end") == [100, 200]) + #expect(offsets("between") == [0, 200]) + #expect(offsets("around") == [25, 175]) + let third: CGFloat = 100 / 3 + #expect(offsets("evenly") == [third, 100 + 2 * third]) + } + + @Test func fixedItemsShrinkInProportion() { + let items = [Item(basis: 300, flexible: false), Item(basis: 100, flexible: false)] + #expect(FlexLayout.distribute(items, width: 200, gap: 0, justify: nil).widths == [150, 50]) + } + + @Test func wrapsByBasisButGrowingItemsNeverWrap() { + let fixed = Array(repeating: Item(basis: 100, flexible: false), count: 5) + #expect(FlexLayout.lines(fixed, width: 330, gap: 10, wrap: true) == [0..<3, 3..<5]) + #expect(FlexLayout.lines(fixed, width: 330, gap: 10, wrap: false) == [0..<5]) + let cards = Array(repeating: Item(basis: 0, flexible: true), count: 5) + #expect(FlexLayout.lines(cards, width: 100, gap: 10, wrap: true) == [0..<5]) + } + + @Test func gapsFollowReactUISpacing() { + let names: [String?] = ["none", "xs", "s", nil, "m", "l", "xl", "2xl"] + let gaps: [CGFloat] = [0, 6, 8, 12, 12, 18, 24, 36] + #expect(names.map(FlexLayout.gap) == gaps) + } + +} From 30f948e80b6d3cfbe29bf3982ec122e9cd1e4e6c Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:09:45 +0530 Subject: [PATCH 28/52] feat(swift-lang): add an MCP tool provider react-lang's Renderer takes an MCP client directly as its toolProvider and unwraps each callTool result. McpToolProvider does the same for a closure that returns the client's raw result, so error results become McpToolErrors (reported as mcp-error) and structuredContent or JSON text becomes the query's data. A closure keeps the package free of any particular MCP client. --- packages/swift-lang/README.md | 11 ++++++++- .../Sources/OpenUILang/QueryManager.swift | 24 +++++++++++++++++++ .../OpenUILangTests/QueryAndFormTests.swift | 19 +++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/packages/swift-lang/README.md b/packages/swift-lang/README.md index 2a55c83e46..b8b7e3d3f4 100644 --- a/packages/swift-lang/README.md +++ b/packages/swift-lang/README.md @@ -212,7 +212,16 @@ let tools = FunctionToolProvider([ OpenUIRenderer(response: text, library: library, toolProvider: tools) ``` -Conform your own type to `ToolProvider` for MCP or other backends; `extractToolResult(_:)` unwraps MCP `callTool` results. +For an MCP server, `McpToolProvider` plays the part of passing an MCP client to react-lang's Renderer: give it a closure that calls the tool and returns the raw result (`{ content, structuredContent, isError }`) as an `OpenUIValue`, and it unwraps it with `extractToolResult(_:)`. Error results reach `onError` as `mcp-error`. It takes a closure so any MCP client works without this package depending on one: + +```swift +let tools = McpToolProvider { name, arguments in + // e.g. a JSON-RPC tools/call to your MCP server, then JSON.parse(result) + try await mcp.callTool(name, arguments) +} +``` + +Conform your own type to `ToolProvider` for other backends. ## JSON Schema Output diff --git a/packages/swift-lang/Sources/OpenUILang/QueryManager.swift b/packages/swift-lang/Sources/OpenUILang/QueryManager.swift index 9c3af3383c..cf8764c258 100644 --- a/packages/swift-lang/Sources/OpenUILang/QueryManager.swift +++ b/packages/swift-lang/Sources/OpenUILang/QueryManager.swift @@ -70,6 +70,30 @@ public struct FunctionToolProvider: ToolProvider { } } +/// A tool provider for an MCP client, like passing one to react-lang's +/// Renderer as its `toolProvider`. `callTool` returns the client's raw result +/// (`{ content, structuredContent, isError }`); the provider unwraps it with +/// `extractToolResult`, so error results become `McpToolError`s, which +/// `onError` reports as `mcp-error`. +/// +/// It takes a closure rather than a client type, so any MCP client works +/// without this package depending on one: convert the client's result to an +/// `OpenUIValue` (for a JSON-RPC result, `JSON.parse` its text). +public struct McpToolProvider: ToolProvider { + public typealias CallTool = + @Sendable (_ name: String, _ arguments: OpenUIObject) async throws -> OpenUIValue + + private let call: CallTool + + public init(callTool: @escaping CallTool) { + call = callTool + } + + public func callTool(_ name: String, arguments: OpenUIObject) async throws -> OpenUIValue { + try extractToolResult(await call(name, arguments)) + } +} + /// A Query statement evaluated against the current state. public struct QueryNode: Sendable { public var statementId: String diff --git a/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift b/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift index 4407bf016a..c641491b8b 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift +++ b/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift @@ -115,6 +115,25 @@ import Testing try extractToolResult(["isError": true, "content": [["type": "text", "text": "bad"]]]) } } + + /// An MCP client as the tool provider, as react-lang's Renderer takes one: + /// raw results are unwrapped, and error results become `mcp-error`. + @Test func mcpClientResultsAreUnwrapped() async throws { + let provider = McpToolProvider { name, arguments in + if name == "fail" { + return ["isError": true, "content": [["type": "text", "text": "quota exceeded"]]] + } + let echo = OpenUIValue.string("{\"echo\":\(JSON.stringify(arguments["q"] ?? .null))}") + return ["content": [["type": "text", "text": echo]]] + } + #expect(try await provider.callTool("search", arguments: ["q": "ada"]) == ["echo": "ada"]) + + let manager = QueryManager(toolProvider: provider) + manager.registerMutations([MutationNode(statementId: "boom", toolName: "fail")]) + #expect(await manager.fireMutation("boom", args: [:]) == false) + #expect(manager.snapshot.errors.first?.code == "mcp-error") + #expect(manager.snapshot.errors.first?.message.contains("quota exceeded") == true) + } } @Suite struct FormRulesTests { From a2fa3cd04e32cacfe81d9ee2a05557e0b6c622db Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:13:36 +0530 Subject: [PATCH 29/52] feat(swift-lang): port the observability bus and stream events Observability.shared ports @openuidev/observability: sinks listen by level or to everything, and emitters skip building events when nothing listens. The runtime publishes react-lang's react-lang:stream events with the same fields (a stable id, phase, updateIndex, the response, parser metadata, errors and timings), so a sink written for the web, like observability-cloud, reads them unchanged. A settled response with errors is an error-level event. StreamObservation ports advanceStreamingObservability, and its tests are react-lang's, case for case. publishObservability: false on the renderer turns the events off, like react-lang's Renderer prop. --- packages/swift-lang/README.md | 20 ++- .../Sources/OpenUILang/Observability.swift | 151 ++++++++++++++++ .../Sources/OpenUILang/Runtime.swift | 62 ++++++- .../Sources/OpenUISwiftUI/OpenUIContext.swift | 4 +- .../OpenUISwiftUI/OpenUIRenderer.swift | 11 +- .../OpenUILangTests/ObservabilityTests.swift | 161 ++++++++++++++++++ 6 files changed, 397 insertions(+), 12 deletions(-) create mode 100644 packages/swift-lang/Sources/OpenUILang/Observability.swift create mode 100644 packages/swift-lang/Tests/OpenUILangTests/ObservabilityTests.swift diff --git a/packages/swift-lang/README.md b/packages/swift-lang/README.md index b8b7e3d3f4..d75027c535 100644 --- a/packages/swift-lang/README.md +++ b/packages/swift-lang/README.md @@ -152,16 +152,26 @@ Schemas serialize to the same JSON Schema `lang-core` libraries produce: `schema ### Rendering -| API | Description | -| ---------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -| `OpenUIRenderer(response:isStreaming:library:initialState:toolProvider:queryLoader:onAction:onStateUpdate:onParseResult:onError:)` | Renders a response. `queryLoader` replaces the small spinner shown while queries load. | -| `OpenUINode(value)` / `OpenUINodes(values)` | Render child props (elements, arrays, text) inside a component. | -| `ComponentProps` | `string`, `text`, `number`, `bool`, `array`, `elements`, `children` accessors that tolerate partial values while streaming. | +| API | Description | +| ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | +| `OpenUIRenderer(response:isStreaming:library:initialState:toolProvider:publishObservability:queryLoader:onAction:onStateUpdate:onParseResult:onError:)` | Renders a response. `queryLoader` replaces the small spinner shown while queries load. | +| `OpenUINode(value)` / `OpenUINodes(values)` | Render child props (elements, arrays, text) inside a component. | +| `ComponentProps` | `string`, `text`, `number`, `bool`, `array`, `elements`, `children` accessors that tolerate partial values while streaming. | ### Errors `onError` receives the same structured errors as react-lang's `onError`, for an automated correction loop: parser validation errors with fix hints (available components, the expected signature), `parse-failed` when a finished response has no root, and failed `Query`/`Mutation` calls. Errors are reported once the response finishes streaming, and `onError([])` is called when they clear or the next response starts. `OpenUIError.jsonRepresentation` gives the same JSON shape as lang-core's `OpenUIError`. +### Observability + +`Observability.shared` ports `@openuidev/observability`: a bus that sinks (logging, analytics, a debugging view) listen to with `listen(_:_:)` or `listenAll(_:)`. As each response streams and settles, the runtime emits react-lang's `react-lang:stream` events with the same fields (a stable `id`, `phase`, `updateIndex`, the response, parser metadata, errors and timings), so a sink built for the web reads them too. A settled response with errors is an `error`-level event. Pass `publishObservability: false` to the renderer to stop them. + +```swift +Observability.shared.listen([.error]) { event in + logger.error("\(event.detail["message"]?.stringValue ?? "")") +} +``` + ### Context Helpers Components read the renderer state from the environment: diff --git a/packages/swift-lang/Sources/OpenUILang/Observability.swift b/packages/swift-lang/Sources/OpenUILang/Observability.swift new file mode 100644 index 0000000000..3eeea6fa05 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUILang/Observability.swift @@ -0,0 +1,151 @@ +import Foundation + +/// How serious an `ObservabilityEvent` is. +public enum ObservabilityLevel: String, Sendable { + case info, warning, error +} + +/// One event on the observability bus. +public struct ObservabilityEvent: Sendable { + public var level: ObservabilityLevel + /// Milliseconds since 1970, like JavaScript's `Date.now()`. + public var timestamp: Double + /// What happened: `kind` names it, the other fields describe it. + public var detail: OpenUIObject +} + +/// Port of `@openuidev/observability`: one shared bus that OpenUI emits events +/// on and sinks (logging, analytics, a debugging view) listen to. +/// +/// The runtime emits a `react-lang:stream` event as each response streams and +/// when it settles, with the same fields as react-lang's, so a sink written +/// for the web reads these too. Listeners are called on the emitting thread. +public final class Observability: @unchecked Sendable { + public typealias Handler = @Sendable (ObservabilityEvent) -> Void + + /// The bus OpenUI emits on. + public static let shared = Observability() + + private let lock = NSLock() + private var listeners: [(id: Int, key: String, handler: Handler)] = [] + private var nextID = 0 + + public init() {} + + /// Whether anything listens, so emitters can skip building events. + public var hasListeners: Bool { lock.withLock { !listeners.isEmpty } } + + /// Milliseconds since 1970, like `Date.now()`. + static func now() -> Double { (Date().timeIntervalSince1970 * 1000).rounded(.down) } + + /// Emits `detail` at `level` to its listeners and to `listenAll` ones. + public func emit(_ level: ObservabilityLevel, _ detail: OpenUIObject) { + let event = ObservabilityEvent(level: level, timestamp: Self.now(), detail: detail) + let targets = lock.withLock { + listeners.filter { $0.key == level.rawValue } + listeners.filter { $0.key == Self.all } + } + for target in targets { target.handler(event) } + } + + public func info(_ detail: OpenUIObject) { emit(.info, detail) } + public func warn(_ detail: OpenUIObject) { emit(.warning, detail) } + public func error(_ detail: OpenUIObject) { emit(.error, detail) } + + /// Listens to every event at `levels`. Call the result to stop. + @discardableResult + public func listen( + _ levels: [ObservabilityLevel], _ handler: @escaping Handler + ) -> @Sendable () -> Void { + let removers = levels.map { subscribe($0.rawValue, handler) } + return { + for remove in removers { remove() } + } + } + + /// Listens to every event. Call the result to stop. + @discardableResult + public func listenAll(_ handler: @escaping Handler) -> @Sendable () -> Void { + subscribe(Self.all, handler) + } + + private static let all = "all" + + private func subscribe(_ key: String, _ handler: @escaping Handler) -> @Sendable () -> Void { + let id = lock.withLock { + nextID += 1 + listeners.append((nextID, key, handler)) + return nextID + } + return { [weak self] in + guard let self else { return } + self.lock.withLock { self.listeners.removeAll { $0.id == id } } + } + } +} + +/// The `kind` of the stream lifecycle events, react-lang's `STREAM_EVENT_KIND`. +public let streamEventKind = "react-lang:stream" + +/// One response's stream lifecycle as react-lang's Renderer publishes it +/// (`advanceStreamingObservability`): a stable id from the first streamed +/// chunk, a `streaming` update for each new chunk, then one `settled` update, +/// repeated only when the errors change. Streaming again starts a new id. +struct StreamObservation: Sendable { + enum Phase: String, Sendable { + case streaming, settled + } + + struct Update: Equatable, Sendable { + var id: String + var phase: Phase + var updateIndex: Int + } + + var id: String? + var updateIndex = 0 + var lastResponse: String? + var hasPublishedStreamingSnapshot = false + var settled = false + var lastSettledErrorKey: String? + var startedAt: Double? + var durationMs: Double? + + /// The update to publish for this state, if any. `settledErrorKey` + /// identifies the errors once settled. + mutating func advance( + isStreaming: Bool, response: String?, settledErrorKey: String?, + idFactory: () -> String = { UUID().uuidString.lowercased() } + ) -> Update? { + if isStreaming { + if settled { self = StreamObservation() } + let id = self.id ?? idFactory() + self.id = id + if hasPublishedStreamingSnapshot && lastResponse == response { return nil } + hasPublishedStreamingSnapshot = true + lastResponse = response + updateIndex += 1 + return Update(id: id, phase: .streaming, updateIndex: updateIndex) + } + guard let id else { return nil } + if settled && (settledErrorKey == nil || lastSettledErrorKey == settledErrorKey) { + return nil + } + updateIndex += 1 + settled = true + lastSettledErrorKey = settledErrorKey + return Update(id: id, phase: .settled, updateIndex: updateIndex) + } + + /// react-lang's `captureStreamTiming`: when the stream started, how long it + /// has run, and its duration, frozen once it settles. + mutating func timing(now: Double = Observability.now()) -> OpenUIObject { + let startedAt = self.startedAt ?? now + self.startedAt = startedAt + if settled, durationMs == nil { durationMs = max(0, now - startedAt) } + var fields: OpenUIObject = [ + "startedAt": .number(startedAt), "elapsedMs": .number(durationMs ?? max(0, now - startedAt)), + ] + if let durationMs { fields["durationMs"] = .number(durationMs) } + return fields + } +} diff --git a/packages/swift-lang/Sources/OpenUILang/Runtime.swift b/packages/swift-lang/Sources/OpenUILang/Runtime.swift index 333b345671..90fe9a4c66 100644 --- a/packages/swift-lang/Sources/OpenUILang/Runtime.swift +++ b/packages/swift-lang/Sources/OpenUILang/Runtime.swift @@ -48,6 +48,11 @@ public final class OpenUIRuntime { private var hasParsed = false /// The errors last passed to `onError`; nil when nothing is reported. private var reportedErrors: [OpenUIError]? + private var streamObservation = StreamObservation() + + /// Whether to publish `react-lang:stream` events on `Observability.shared` + /// (react-lang's `publishObservability`). + public var publishesObservability = true public init( library: some ComponentLibrary, initialState: OpenUIObject? = nil, @@ -62,7 +67,11 @@ public final class OpenUIRuntime { guard let self, !self.initializingStore else { return } self.onStateUpdate?(self.store.snapshot) }) - unsubscribers.append(queries.subscribe { [weak self] in self?.reportErrors() }) + unsubscribers.append( + queries.subscribe { [weak self] in + self?.reportErrors() + self?.publishStream() + }) } /// Stops query refreshes and drops listeners. @@ -89,7 +98,10 @@ public final class OpenUIRuntime { /// Feeds the latest full response text. Appended text parses incrementally. public func update(response: String?, isStreaming: Bool) { self.isStreaming = isStreaming - defer { reportErrors() } + defer { + reportErrors() + publishStream() + } let changed = !hasParsed || response != self.response hasParsed = true self.response = response @@ -165,6 +177,52 @@ public final class OpenUIRuntime { onError(errors) } + // MARK: Observability + + /// Publishes the stream lifecycle like react-lang's + /// `useStreamingObservability`: each streamed chunk, then the settled + /// response with its errors (as an error event when there are any). + private func publishStream() { + guard publishesObservability else { return } + let errors = isStreaming ? [] : self.errors + let errorJSON = errors.map(\.jsonRepresentation) + guard + let update = streamObservation.advance( + isStreaming: isStreaming, response: response, + settledErrorKey: isStreaming ? nil : JSON.stringify(.array(errorJSON))) + else { return } + let timing = streamObservation.timing() + guard Observability.shared.hasListeners else { return } + + var detail: OpenUIObject = [ + "id": .string(update.id), "kind": .string(streamEventKind), + "phase": .string(update.phase.rawValue), "updateIndex": .number(Double(update.updateIndex)), + "response": response.map(OpenUIValue.string) ?? .null, + "responseLength": .number(Double(response?.utf16.count ?? 0)), + ] + if let meta = parseResult?.meta { + detail["parser"] = [ + "incomplete": .bool(meta.incomplete), + "unresolved": .array(meta.unresolved.map { .string($0) }), + "orphaned": .array(meta.orphaned.map { .string($0) }), + "statementCount": .number(Double(meta.statementCount)), + ] + } + let settled = update.phase == .settled + if settled { + detail["errors"] = .array(errorJSON) + detail["errorCount"] = .number(Double(errors.count)) + } + for (key, value) in timing { detail[key] = value } + detail["message"] = .string( + !settled + ? "OpenUI Lang is streaming" + : errors.isEmpty + ? "OpenUI Lang settled" + : "OpenUI Lang settled with \(errors.count) error\(errors.count == 1 ? "" : "s")") + Observability.shared.emit(settled && !errors.isEmpty ? .error : .info, detail) + } + /// A validation error as an `OpenUIError`, with the fix hint lang-core's /// `enrichErrors` adds. private func withHint(_ error: ValidationError) -> OpenUIError { diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift index a332756581..260b5e1c33 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIContext.swift @@ -46,7 +46,8 @@ public final class OpenUIContext { /// ``update(response:isStreaming:)`` is called. public init( library: SwiftUILibrary, initialState: OpenUIObject? = nil, - toolProvider: (any ToolProvider)? = nil, response: String? = nil, isStreaming: Bool = false + toolProvider: (any ToolProvider)? = nil, publishObservability: Bool = true, + response: String? = nil, isStreaming: Bool = false ) { self.library = library self.runtime = OpenUIRuntime( @@ -57,6 +58,7 @@ public final class OpenUIContext { runtime.onError = { [weak self] errors in self?.onError?(errors) } unsubscribers.append(runtime.store.subscribe { [weak self] in self?.revision += 1 }) unsubscribers.append(runtime.queries.subscribe { [weak self] in self?.revision += 1 }) + runtime.publishesObservability = publishObservability runtime.preload(response: response, isStreaming: isStreaming) } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift index 6d23c9d0eb..973de35d17 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUIRenderer.swift @@ -31,6 +31,7 @@ public struct OpenUIRenderer: View { /// - library: The components the response may use. Changing it requires a new view identity. /// - initialState: Restored `$state` and form values, e.g. from a saved conversation. /// - toolProvider: Handles `Query` and `Mutation` tool calls. + /// - publishObservability: Whether to publish stream events on `Observability.shared`. /// - queryLoader: Shown in the top trailing corner while queries load. /// - onAction: Called for actions the host handles (continue the conversation, open a URL). /// A trailing closure binds here. @@ -41,7 +42,7 @@ public struct OpenUIRenderer: View { public init( response: String?, isStreaming: Bool = false, library: SwiftUILibrary, initialState: OpenUIObject? = nil, toolProvider: (any ToolProvider)? = nil, - queryLoader: QueryLoader, + publishObservability: Bool = true, queryLoader: QueryLoader, onAction: ((ActionEvent) -> Void)? = nil, onStateUpdate: ((OpenUIObject) -> Void)? = nil, onParseResult: ((ParseResult?) -> Void)? = nil, @@ -61,7 +62,8 @@ public struct OpenUIRenderer: View { wrappedValue: ContextHolder( OpenUIContext( library: library, initialState: initialState, toolProvider: toolProvider, - response: response, isStreaming: isStreaming))) + publishObservability: publishObservability, response: response, + isStreaming: isStreaming))) } public var body: some View { @@ -106,14 +108,15 @@ extension OpenUIRenderer where QueryLoader == DefaultQueryLoader { public init( response: String?, isStreaming: Bool = false, library: SwiftUILibrary, initialState: OpenUIObject? = nil, toolProvider: (any ToolProvider)? = nil, - onAction: ((ActionEvent) -> Void)? = nil, + publishObservability: Bool = true, onAction: ((ActionEvent) -> Void)? = nil, onStateUpdate: ((OpenUIObject) -> Void)? = nil, onParseResult: ((ParseResult?) -> Void)? = nil, onError: (([OpenUIError]) -> Void)? = nil ) { self.init( response: response, isStreaming: isStreaming, library: library, initialState: initialState, - toolProvider: toolProvider, queryLoader: DefaultQueryLoader(), onAction: onAction, + toolProvider: toolProvider, publishObservability: publishObservability, + queryLoader: DefaultQueryLoader(), onAction: onAction, onStateUpdate: onStateUpdate, onParseResult: onParseResult, onError: onError) } } diff --git a/packages/swift-lang/Tests/OpenUILangTests/ObservabilityTests.swift b/packages/swift-lang/Tests/OpenUILangTests/ObservabilityTests.swift new file mode 100644 index 0000000000..5b411303dd --- /dev/null +++ b/packages/swift-lang/Tests/OpenUILangTests/ObservabilityTests.swift @@ -0,0 +1,161 @@ +import Foundation +import Testing + +@testable import OpenUILang + +/// react-lang's streaming observability tests, ported. +@Suite struct StreamObservationTests { + typealias Update = StreamObservation.Update + + @Test func noEventForContentThatWasNeverStreamed() { + var state = StreamObservation() + var calls = 0 + let update = state.advance( + isStreaming: false, response: #"root = Card("done")"#, settledErrorKey: "[]", + idFactory: { + calls += 1 + return "stream-1" + }) + #expect(update == nil) + #expect(calls == 0) + } + + @Test func oneStableIDForEveryUpdateAndTheSettledEvent() { + var state = StreamObservation() + var calls = 0 + let id = { + calls += 1 + return "stream-1" + } + #expect( + state.advance(isStreaming: true, response: "root = Car", settledErrorKey: nil, idFactory: id) + == Update(id: "stream-1", phase: .streaming, updateIndex: 1)) + #expect( + state.advance( + isStreaming: true, response: #"root = Card("done")"#, settledErrorKey: nil, idFactory: id) + == Update(id: "stream-1", phase: .streaming, updateIndex: 2)) + #expect( + state.advance( + isStreaming: false, response: #"root = Card("done")"#, settledErrorKey: "[]", idFactory: id) + == Update(id: "stream-1", phase: .settled, updateIndex: 3)) + #expect(calls == 1) + } + + @Test func emitsOncePerResponseAndUnchangedSettledSnapshot() { + var state = StreamObservation() + let id = { "stream-1" } + #expect( + state.advance(isStreaming: true, response: "root = Car", settledErrorKey: nil, idFactory: id) + != nil) + #expect( + state.advance(isStreaming: true, response: "root = Car", settledErrorKey: nil, idFactory: id) + == nil) + #expect( + state.advance( + isStreaming: false, response: "root = Car", settledErrorKey: "[]", idFactory: id) != nil) + #expect( + state.advance( + isStreaming: false, response: "root = Car", settledErrorKey: "[]", idFactory: id) == nil) + } + + @Test func startsANewIDWhenASettledRendererStreamsAgain() { + var state = StreamObservation() + var ids = ["stream-1", "stream-2"] + let id = { ids.removeFirst() } + #expect( + state.advance(isStreaming: true, response: "first", settledErrorKey: nil, idFactory: id) + == Update(id: "stream-1", phase: .streaming, updateIndex: 1)) + #expect( + state.advance(isStreaming: false, response: "first", settledErrorKey: "[]", idFactory: id) + == Update(id: "stream-1", phase: .settled, updateIndex: 2)) + #expect( + state.advance(isStreaming: true, response: "second", settledErrorKey: nil, idFactory: id) + == Update(id: "stream-2", phase: .streaming, updateIndex: 1)) + #expect( + state.advance(isStreaming: false, response: "second", settledErrorKey: "[]", idFactory: id) + == Update(id: "stream-2", phase: .settled, updateIndex: 2)) + #expect(ids.isEmpty) + } + + @Test func republishesSettledWhenTheErrorSnapshotChanges() { + var state = StreamObservation() + let id = { "stream-1" } + _ = state.advance( + isStreaming: true, response: "root = Card()", settledErrorKey: nil, idFactory: id) + _ = state.advance( + isStreaming: false, response: "root = Card()", settledErrorKey: "[]", idFactory: id) + let queryError = #"[{"code":"query-error"}]"# + #expect( + state.advance( + isStreaming: false, response: "root = Card()", settledErrorKey: queryError, idFactory: id) + == Update(id: "stream-1", phase: .settled, updateIndex: 3)) + #expect( + state.advance( + isStreaming: false, response: "root = Card()", settledErrorKey: queryError, idFactory: id) + == nil) + #expect( + state.advance( + isStreaming: false, response: "root = Card()", + settledErrorKey: #"[{"code":"query-error"},{"code":"tool-failed"}]"#, idFactory: id) + == Update(id: "stream-1", phase: .settled, updateIndex: 4)) + } +} + +@Suite struct ObservabilityBusTests { + final class Log: @unchecked Sendable { + private let lock = NSLock() + private var items: [ObservabilityEvent] = [] + func append(_ event: ObservabilityEvent) { lock.withLock { items.append(event) } } + var events: [ObservabilityEvent] { lock.withLock { items } } + } + + @Test func deliversByLevelAndToListenAll() { + let bus = Observability() + let errors = Log() + let all = Log() + let stopErrors = bus.listen([.error]) { errors.append($0) } + let stopAll = bus.listenAll { all.append($0) } + bus.info(["kind": "a"]) + bus.error(["kind": "b"]) + #expect(errors.events.map(\.detail["kind"]) == ["b"]) + #expect(all.events.map(\.level) == [.info, .error]) + stopErrors() + stopAll() + bus.error(["kind": "c"]) + #expect(errors.events.count == 1) + #expect(!bus.hasListeners) + } + + /// The runtime publishes react-lang's stream events: one per streamed + /// chunk, then the settled response with its errors. + @MainActor + @Test func runtimePublishesTheStreamLifecycle() { + let log = Log() + // The bus is shared with tests running in parallel; keep only ours. + let marker = "observability-\(UUID().uuidString)" + let stop = Observability.shared.listenAll { event in + if event.detail["response"]?.stringValue?.contains(marker) == true { log.append(event) } + } + defer { stop() } + + let runtime = OpenUIRuntime(library: FixtureLibrary(schemaName: "test")) + let full = #"root = Card([Text("\#(marker)"), Mystery()])"# + runtime.update(response: #"root = Card([Text("\#(marker)""#, isStreaming: true) + runtime.update(response: full, isStreaming: true) + runtime.update(response: full, isStreaming: true) + runtime.update(response: full, isStreaming: false) + + let events = log.events.map { (level: $0.level, detail: OpenUIValue.object($0.detail)) } + #expect(events.map { $0.detail["phase"] } == ["streaming", "streaming", "settled"]) + #expect(Set(events.compactMap { $0.detail["id"].stringValue }).count == 1) + #expect(events.map { $0.detail["updateIndex"] } == [1, 2, 3]) + let settled = events.last! + #expect(settled.detail["kind"] == .string(streamEventKind)) + #expect(settled.level == .error) + #expect(settled.detail["errorCount"] == 1) + #expect(settled.detail["errors"].arrayValue?.first?["code"] == "unknown-component") + #expect(settled.detail["parser"]["statementCount"] == 1) + #expect(settled.detail["message"] == "OpenUI Lang settled with 1 error") + #expect(settled.detail["durationMs"].numberValue != nil) + } +} From 1de63875f3c469bc474df84d9b197b0a83ea8bff Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:35:29 +0530 Subject: [PATCH 30/52] fix(swift-lang): only count changed editable table cells as edits On the Mac a focused text field writes its text back when editing ends, so clicking or tabbing through cells stored their unchanged values as edits and the table offered to save changes nobody made. Text equal to the data is no longer an edit, and typing the original back undoes one. The bookkeeping moves into TableEdits so it can be tested on its own. --- .../Components/SelectionComponents.swift | 32 +++++++++++++++---- .../OpenUISwiftUITests/RendererTests.swift | 18 +++++++++++ 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift index 4ba4ed706b..0510bffcf9 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift @@ -200,7 +200,7 @@ private struct OptionCardTile: View { /// react-ui. struct EditableTableView: View { let props: ComponentProps - @State private var edits: [String: [Int: String]] = [:] + @State private var edits = TableEdits() @Environment(OpenUIContext.self) private var context @Environment(\.openUITheme) private var theme @@ -208,7 +208,7 @@ struct EditableTableView: View { let columns = props.array("columns") let rows = props.array("data") let name = props.string("name") ?? "editable-table" - let changed = edits.values.reduce(0) { $0 + $1.count } + let changed = edits.count VStack(alignment: .leading, spacing: theme.compactSpacing) { ScrollView(.horizontal, showsIndicators: false) { Grid(alignment: .leading, horizontalSpacing: 10, verticalSpacing: 6) { @@ -236,13 +236,13 @@ struct EditableTableView: View { Text("\(changed) unsaved change\(changed == 1 ? "" : "s")").font(.caption) .foregroundStyle(.secondary) Spacer() - Button("Reset") { edits = [:] }.buttonStyle(.borderless) + Button("Reset") { edits = TableEdits() }.buttonStyle(.borderless) Button("Save Changes") { let saved = OpenUIValue.array( rows.map { row in let id = displayText(row["id"]) let values = (0.. OpenUIValue in - if let edit = edits[id]?[index] { + if let edit = edits[id, index] { let number = jsStringToNumber(edit) let numeric = columns[index]["type"].stringValue == "number" && !number.isNaN return numeric ? .number(number) : .string(edit) @@ -254,7 +254,7 @@ struct EditableTableView: View { context.runtime.setFieldValue( form: name, componentType: "EditableTable", name: name, value: saved) context.triggerAction("Save Changes", form: name) - edits = [:] + edits = TableEdits() } .modifier(ProminentButton()) } @@ -267,9 +267,10 @@ struct EditableTableView: View { -> some View { let width = column["width"].numberValue.map { CGFloat($0) } ?? 120 + let original = displayText(value ?? .null) let binding = Binding( - get: { edits[rowId]?[index] ?? displayText(value ?? .null) }, - set: { edits[rowId, default: [:]][index] = $0 }) + get: { edits[rowId, index] ?? original }, + set: { edits.set($0, row: rowId, column: index, original: original) }) return Group { if column["type"].stringValue == "select", let options = column["options"].arrayValue { Picker("", selection: binding) { @@ -286,6 +287,23 @@ struct EditableTableView: View { } } +/// An editable table's unsaved edits, by row id and column. Only text that +/// differs from the data is an edit: a focused field writes its text back +/// unchanged, which must not count as a change. +struct TableEdits: Equatable { + private var rows: [String: [Int: String]] = [:] + + /// How many cells have unsaved edits. + var count: Int { rows.values.reduce(0) { $0 + $1.count } } + + subscript(row: String, column: Int) -> String? { rows[row]?[column] } + + mutating func set(_ text: String, row: String, column: Int, original: String) { + rows[row, default: [:]][column] = text == original ? nil : text + if rows[row]?.isEmpty == true { rows[row] = nil } + } +} + extension Array { subscript(safe index: Int) -> Element? { indices.contains(index) ? self[index] : nil } } diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 9dd9ec50bb..dd66da0bd5 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -736,3 +736,21 @@ let globalTestLibrary = SwiftUILibrary( } } + +/// The editable table's edit bookkeeping. +@Suite struct TableEditsTests { + @Test func onlyChangedTextIsAnEdit() { + var edits = TableEdits() + // A focused field writes its text back unchanged: not an edit. + edits.set("Alex", row: "1", column: 0, original: "Alex") + #expect(edits.count == 0) + edits.set("Alexx", row: "1", column: 0, original: "Alex") + edits.set("Ops", row: "2", column: 1, original: "Eng") + #expect(edits.count == 2) + #expect(edits["1", 0] == "Alexx") + // Typing the original back undoes the edit. + edits.set("Alex", row: "1", column: 0, original: "Alex") + #expect(edits.count == 1) + #expect(edits["1", 0] == nil) + } +} From ee8ea127cce87301cc9dd08bf0933623a147eee9 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:35:46 +0530 Subject: [PATCH 31/52] feat(swift-lang): move between editable table cells with the keyboard react-ui's EditableTable takes spreadsheet keys. With a hardware keyboard, Up and Down now move between rows in the same column, and Enter keeps the edit and moves down; Tab already moved across. Cells stay text fields rather than react-ui's select-then-edit, which suits touch. Escape isn't ported: a focused Mac text field keeps showing its typed text after the value is reverted, so it would look undone without being undone. --- .../Components/SelectionComponents.swift | 39 +++++++++-- .../OpenUISwiftUITests/RendererTests.swift | 65 +++++++++++++++++++ 2 files changed, 97 insertions(+), 7 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift index 0510bffcf9..ddd85ef554 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift @@ -201,6 +201,7 @@ private struct OptionCardTile: View { struct EditableTableView: View { let props: ComponentProps @State private var edits = TableEdits() + @FocusState private var focus: Cell? @Environment(OpenUIContext.self) private var context @Environment(\.openUITheme) private var theme @@ -219,13 +220,13 @@ struct EditableTableView: View { } } Divider() - ForEach(Array(rows.enumerated()), id: \.offset) { _, row in + ForEach(Array(rows.enumerated()), id: \.offset) { rowIndex, row in let id = displayText(row["id"]) GridRow { ForEach(Array(columns.enumerated()), id: \.offset) { index, column in cell( - rowId: id, index: index, column: column, - value: row["values"].arrayValue?[safe: index]) + Cell(row: rowIndex, column: index), rowId: id, column: column, + value: row["values"].arrayValue?[safe: index], rowCount: rows.count) } } } @@ -263,9 +264,24 @@ struct EditableTableView: View { .disabled(context.isStreaming) } - private func cell(rowId: String, index: Int, column: OpenUIValue, value: OpenUIValue?) - -> some View - { + /// A cell's place in the table, for keyboard focus. + private struct Cell: Hashable { + let row: Int + let column: Int + } + + /// Moves focus `rows` rows from `cell`, staying in its column. + private func move(_ rows: Int, from cell: Cell, rowCount: Int) -> KeyPress.Result { + let row = cell.row + rows + guard (0.. some View { + let index = position.column let width = column["width"].numberValue.map { CGFloat($0) } ?? 120 let original = displayText(value ?? .null) let binding = Binding( @@ -280,7 +296,16 @@ struct EditableTableView: View { } .labelsHidden() } else { - TextField("", text: binding).textFieldStyle(.roundedBorder) + // react-ui's spreadsheet keys, for a hardware keyboard: Enter keeps + // the edit and moves down, Up and Down move between rows. Tab already + // moves across. + TextField("", text: binding) + .textFieldStyle(.roundedBorder) + .focused($focus, equals: position) + .onSubmit { _ = move(1, from: position, rowCount: rowCount) } + .onKeyPress(.upArrow) { move(-1, from: position, rowCount: rowCount) } + .onKeyPress(.downArrow) { move(1, from: position, rowCount: rowCount) } + } } .frame(width: width) diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index dd66da0bd5..735b737677 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -259,6 +259,71 @@ import Testing #expect(box.state["$open"] == false) } + /// The editable table's keys with a keyboard: Down and Up move between + /// rows, and Enter keeps the edit and moves down. + @Test func editableTableKeys() { + let input = """ + root = Card([t]) + t = EditableTable("roster", [{type: "text", key: "name", header: "Name"}], [{id: "1", values: ["Alex"]}, {id: "2", values: ["Jamie"]}, {id: "3", values: ["Sam"]}]) + """ + let host = NSHostingView( + rootView: OpenUIRenderer(response: input, library: OpenUIChatLibrary.library) + .frame(width: 420, height: 300)) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 420, height: 300), styleMask: [.titled], + backing: .buffered, defer: false) + window.isReleasedWhenClosed = false + window.contentView = host + window.makeKeyAndOrderFront(nil) + defer { window.close() } + func settle() { RunLoop.main.run(until: Date().addingTimeInterval(0.2)) } + func fields(_ view: NSView) -> [NSTextField] { + let own = (view as? NSTextField).map { [$0] } ?? [] + return own + view.subviews.flatMap(fields) + } + func key(_ code: UInt16, _ characters: String) { + for type in [NSEvent.EventType.keyDown, .keyUp] { + window.sendEvent( + NSEvent.keyEvent( + with: type, location: .zero, modifierFlags: [], timestamp: 0, + windowNumber: window.windowNumber, context: nil, characters: characters, + charactersIgnoringModifiers: characters, isARepeat: false, keyCode: code)!) + } + settle() + } + /// The text of the field being edited. + func focused() -> String? { (window.firstResponder as? NSText)?.string } + /// Waits for focus to land on the field showing `text` (CI is slower). + func focuses(_ text: String) -> Bool { + for _ in 0..<30 where focused() != text { settle() } + return focused() == text + } + settle() + let cells = fields(host).filter(\.isEditable).sorted { + $0.convert(.zero, to: nil).y > $1.convert(.zero, to: nil).y + } + guard cells.count == 3 else { + Issue.record("expected 3 cells, found \(cells.count)") + return + } + window.makeFirstResponder(cells[0]) + settle() + #expect(focuses("Alex")) + key(125, "\u{F701}") // Down + #expect(focuses("Jamie")) + key(126, "\u{F700}") // Up + #expect(focuses("Alex")) + (window.firstResponder as? NSTextView)?.insertText( + "x", replacementRange: NSRange(location: 4, length: 0)) + key(36, "\r") // Enter + #expect(focuses("Jamie")) + #expect(cells[0].stringValue == "Alexx") + key(125, "\u{F701}") // Down + key(125, "\u{F701}") // Down at the last row stays there + #expect(focuses("Sam")) + #expect(cells[0].stringValue == "Alexx") + } + /// The bug vishxrad hit in the Angular port: an input recreated on every /// update loses focus mid-typing. The AppKit text field behind the SwiftUI /// input must be the same object across streamed updates and typing. From 23d77c7664b72a3d126a09ad7876504719202c27 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:38:13 +0530 Subject: [PATCH 32/52] feat(swift-lang): add per-chart palettes and status colors to the theme OpenUITheme gets react-ui's per-chart palettes (barChartPalette, lineChartPalette and the rest). Each chart uses its own, then chartPalette, then the default ramp, as react-ui's resolvePalette does, with an empty palette counting as none. The single stacked bar uses the bar palette, as react-ui's does. It also gets info, success, alert and danger colors for callouts, tags, icon badges, trends, form and slider errors and the code block's copied state, which used hardcoded system colors. The defaults are those same colors. --- packages/swift-lang/README.md | 2 +- .../Components/CardComponents.swift | 13 ++++--- .../Components/ChartComponents.swift | 16 ++++---- .../Components/ContentComponents.swift | 7 ++-- .../Components/FormComponents.swift | 10 +++-- .../Components/IconComponents.swift | 3 +- .../Sources/OpenUISwiftUI/Theme.swift | 39 +++++++++++++++---- .../OpenUISwiftUITests/RendererTests.swift | 25 ++++++++++++ 8 files changed, 86 insertions(+), 29 deletions(-) diff --git a/packages/swift-lang/README.md b/packages/swift-lang/README.md index d75027c535..417a35b468 100644 --- a/packages/swift-lang/README.md +++ b/packages/swift-lang/README.md @@ -122,7 +122,7 @@ let prompt = OpenUIChatLibrary.library.prompt(ChatComponents.promptOptions) let systemMessage = try OpenUIChatLibrary.library.cloudConfig(ChatComponents.promptOptions) ``` -The views follow react-ui's layouts and behavior rather than restyling them: card blocks use the same responsive grid (one column on phones), tabs and sections follow the stream until the user picks one, charts use react-ui's palette, curves and number formats, with its legends (tap a key to hide that series) and tooltips (hover with a pointer, or tap), and `[n]` citations resolve against the card's sources. Lucide icon names map to SF Symbols with the same category fallbacks. Spacing, fills and corner radii come from `OpenUITheme`, which follows react-ui's design tokens; override it with `.environment(\.openUITheme, theme)`. Its `accent` and `onAccent` color primary buttons, selections and steps (the renderer also tints controls with `accent`), and `chartPalette` replaces the default chart ramp, like react-ui's `defaultChartPalette`. +The views follow react-ui's layouts and behavior rather than restyling them: card blocks use the same responsive grid (one column on phones), tabs and sections follow the stream until the user picks one, charts use react-ui's palette, curves and number formats, with its legends (tap a key to hide that series) and tooltips (hover with a pointer, or tap), and `[n]` citations resolve against the card's sources. Lucide icon names map to SF Symbols with the same category fallbacks. Spacing, fills and corner radii come from `OpenUITheme`, which follows react-ui's design tokens; override it with `.environment(\.openUITheme, theme)`. Its `accent` and `onAccent` color primary buttons, selections and steps (the renderer also tints controls with `accent`), and `chartPalette` replaces the default chart ramp, like react-ui's `defaultChartPalette`, with a palette per chart (`barChartPalette` and the rest) taking precedence. `info`, `success`, `alert` and `danger` color callouts, tags, trends and form errors. The schemas in `ChatComponents` live in `OpenUILang`, without SwiftUI, so a Swift server can build the chat prompt too. They're generated from `openuiChatLibrary` (see [Testing Locally](#testing-locally)). diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift index dd38cbff4f..c1d7df56cf 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift @@ -582,6 +582,7 @@ struct TextLineView: View { let props: ComponentProps let bold: Bool @Environment(\.openUITextAlignment) private var alignment + @Environment(\.openUITheme) private var theme var body: some View { VStack(alignment: alignment == .trailing ? .trailing : .leading, spacing: 2) { @@ -608,8 +609,8 @@ struct TextLineView: View { private func subtextColor(_ subtext: String) -> Color { guard props.string("subtextVariant") == "metric" else { return .secondary } - if subtext.hasPrefix("+") { return .green } - if subtext.hasPrefix("-") || subtext.hasPrefix("−") { return .red } + if subtext.hasPrefix("+") { return theme.success } + if subtext.hasPrefix("-") || subtext.hasPrefix("−") { return theme.danger } return .secondary } } @@ -667,7 +668,7 @@ private struct IconBadge: View { private var colors: (Color, Color) { switch variant { case "info", "success", "warning", "danger": - let color = statusColor(variant) + let color = theme.status(variant) return (color, color.opacity(0.14)) case "inverted": return (Color(white: 0.98), Color.primary) case "filled": return (theme.onAccent, theme.accent) @@ -757,9 +758,11 @@ struct MetricIndicatorWithStrikethroughView: View { } } -/// `{ direction, value }` as an arrow and percentage, green up, red down. +/// `{ direction, value }` as an arrow and percentage, in the success color +/// going up and the danger color going down. private struct TrendLabel: View { let trend: OpenUIValue + @Environment(\.openUITheme) private var theme var body: some View { if let value = trend["value"].numberValue { @@ -769,7 +772,7 @@ private struct TrendLabel: View { Text("\(jsNumberToString(value))%") } .font(.caption.weight(.medium).monospacedDigit()) - .foregroundStyle(up ? .green : .red) + .foregroundStyle(up ? theme.success : theme.danger) } } } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift index 98d86f9cac..46bb1e714c 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift @@ -217,7 +217,7 @@ struct BarChartView: View { var body: some View { let all = seriesPoints(props) let points = all.filter { !hidden.contains($0.series) } - let series = SeriesColors(seriesNames(props), theme.chartPalette) + let series = SeriesColors(seriesNames(props), theme.chartRamp(theme.barChartPalette)) let labels = labelOrder(props) let stacked = props.string("variant") == "stacked" ChartFrame(props, isEmpty: all.isEmpty, legend: series.legend, hidden: $hidden) { @@ -258,7 +258,7 @@ struct HorizontalBarChartView: View { var body: some View { let all = seriesPoints(props) let points = all.filter { !hidden.contains($0.series) } - let series = SeriesColors(seriesNames(props), theme.chartPalette) + let series = SeriesColors(seriesNames(props), theme.chartRamp(theme.horizontalBarChartPalette)) let stacked = props.string("variant") == "stacked" let labels = labelOrder(props) ChartFrame(props, isEmpty: all.isEmpty, legend: series.legend, hidden: $hidden) { @@ -312,7 +312,7 @@ struct LineChartView: View { let method = interpolation(props.string("variant")) let all = seriesPoints(props) let points = all.filter { !hidden.contains($0.series) } - let series = SeriesColors(seriesNames(props), theme.chartPalette) + let series = SeriesColors(seriesNames(props), theme.chartRamp(theme.lineChartPalette)) ChartFrame(props, isEmpty: all.isEmpty, legend: series.legend, hidden: $hidden) { Chart(points) { point in LineMark(x: .value("Label", point.label), y: .value("Value", point.value)) @@ -356,7 +356,7 @@ struct AreaChartView: View { var body: some View { let method = interpolation(props.string("variant")) - let series = SeriesColors(seriesNames(props), theme.chartPalette) + let series = SeriesColors(seriesNames(props), theme.chartRamp(theme.areaChartPalette)) let all = seriesPoints(props) let points = all.filter { !hidden.contains($0.series) } ChartFrame(props, isEmpty: all.isEmpty, legend: series.legend, hidden: $hidden) { @@ -454,7 +454,7 @@ struct PieChartView: View { @Environment(\.openUITheme) private var theme var body: some View { - let all = sortedSlices(slices(props), theme.chartPalette) + let all = sortedSlices(slices(props), theme.chartRamp(theme.pieChartPalette)) let visible = all.filter { !hidden.contains(String($0.slice.id)) } let donut = props.string("variant") == "donut" let semi = props.string("appearance") == "semiCircular" @@ -524,7 +524,7 @@ struct RadialChartView: View { @Environment(\.openUITheme) private var theme var body: some View { - let all = sortedSlices(slices(props), theme.chartPalette) + let all = sortedSlices(slices(props), theme.chartRamp(theme.radialChartPalette)) let visible = all.filter { !hidden.contains(String($0.slice.id)) } let maximum = max(visible.map(\.slice.value).max() ?? 1, 1) VStack(spacing: 12) { @@ -569,7 +569,7 @@ struct SingleStackedBarChartView: View { var body: some View { let data = slices(props) - let ramp = theme.chartPalette.flatMap { $0.isEmpty ? nil : $0 } ?? ChartPalette.ocean + let ramp = theme.chartRamp(theme.barChartPalette) ?? ChartPalette.ocean let total = data.reduce(0) { $0 + $1.value } let share = { (slice: Slice) in total > 0 ? slice.value / total : 0 } let color = { (slice: Slice) in ramp[slice.id % ramp.count] } @@ -735,7 +735,7 @@ struct RadarChartView: View { let all = props.children("series").map { series in (name: series.text("category"), values: series.array("values").map { $0.numberValue ?? 0 }) } - let colors = SeriesColors(all.map(\.name), theme.chartPalette) + let colors = SeriesColors(all.map(\.name), theme.chartRamp(theme.radarChartPalette)) let series = all.filter { !hidden.contains($0.name) } let maximum = max(series.flatMap(\.values).max() ?? 1, 1) VStack(spacing: 12) { diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift index 951fc06d25..74459163da 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift @@ -194,7 +194,7 @@ private struct Banner: View { @Environment(\.openUITheme) private var theme var body: some View { - let color = statusColor(variant) + let color = theme.status(variant) HStack(alignment: .top, spacing: 10) { Image(systemName: symbol).foregroundStyle(color) VStack(alignment: .leading, spacing: 2) { @@ -241,6 +241,7 @@ struct CodeBlockContent: View { let theme: SyntaxHighlighter.Theme @State private var copied = false @State private var hovering = false + @Environment(\.openUITheme) private var openUITheme var body: some View { ScrollView(.horizontal, showsIndicators: false) { @@ -282,10 +283,10 @@ struct CodeBlockContent: View { Image(systemName: copied ? "checkmark" : "doc.on.doc") .font(.caption.weight(.semibold)) .contentTransition(.symbolEffect(.replace)) - .foregroundStyle(copied ? Color.green : Color.primary) + .foregroundStyle(copied ? openUITheme.success : Color.primary) .frame(width: 26, height: 26) .background( - copied ? Color.green.opacity(0.15) : Color.platformElevatedBackground, + copied ? openUITheme.success.opacity(0.15) : Color.platformElevatedBackground, in: RoundedRectangle(cornerRadius: 6) ) .overlay(RoundedRectangle(cornerRadius: 6).strokeBorder(Color.primary.opacity(0.12))) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift index 76974d580d..5d5daccd26 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift @@ -21,6 +21,7 @@ struct FormView: View { struct FormControlView: View { let props: ComponentProps @Environment(FormValidation.self) private var validation: FormValidation? + @Environment(\.openUITheme) private var theme var body: some View { let input = props.children("input").first @@ -30,7 +31,8 @@ struct FormControlView: View { Text(props.text("label") + (required ? "*" : "")).font(.subheadline.weight(.medium)) OpenUINode(props["input"]) if let fieldName, let error = validation?.error(for: fieldName) { - Label(error, systemImage: "exclamationmark.circle").font(.caption).foregroundStyle(.red) + Label(error, systemImage: "exclamationmark.circle").font(.caption).foregroundStyle( + theme.danger) } else if let hint = props.string("hint"), !hint.isEmpty { Text(hint).font(.caption).foregroundStyle(.secondary) } @@ -444,6 +446,7 @@ struct SliderView: View { @Environment(OpenUIContext.self) private var context @Environment(\.openUIFormName) private var form @Environment(FormValidation.self) private var validation: FormValidation? + @Environment(\.openUITheme) private var theme var body: some View { let state = FieldContext(props, context: context, form: form) @@ -475,7 +478,7 @@ struct SliderView: View { } if !context.isStreaming, let error = errors.first(where: { !$0.isEmpty }) { Label(error, systemImage: "exclamationmark.circle") - .font(.caption).foregroundStyle(.red) + .font(.caption).foregroundStyle(theme.danger) } if current.count > 1 { RangeSlider( @@ -594,6 +597,7 @@ private struct SliderValueField: View { let onChange: @MainActor (Double) -> Void @State private var text = "" @FocusState private var focused: Bool + @Environment(\.openUITheme) private var theme var body: some View { TextField("Value", text: $text) @@ -605,7 +609,7 @@ private struct SliderValueField: View { .background(Color.primary.opacity(0.05), in: RoundedRectangle(cornerRadius: 6)) .overlay( RoundedRectangle(cornerRadius: 6) - .strokeBorder(hasError ? Color.red : Color.primary.opacity(0.1)) + .strokeBorder(hasError ? theme.danger : Color.primary.opacity(0.1)) ) .focused($focused) #if os(iOS) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift index 9d724b3eeb..166dd24082 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift @@ -401,10 +401,11 @@ struct TagLabel: View { let size: String? let variant: String? @Environment(\.openUITagOnImage) private var onImage + @Environment(\.openUITheme) private var theme var body: some View { let neutral = variant == nil || variant == "neutral" - let color = neutral ? Color.secondary : statusColor(variant) + let color = neutral ? Color.secondary : theme.status(variant) HStack(spacing: 4) { if let symbol { Image(systemName: symbol) } Text(text) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift index cba068fb34..71b6ea1371 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Theme.swift @@ -31,6 +31,21 @@ public struct OpenUITheme: Sendable { /// that charts pick from the middle outwards. `nil` uses react-ui's default /// blue ramp. public var chartPalette: [Color]? + /// A palette for one kind of chart, like react-ui's `barChartPalette` and + /// the rest. A chart uses its own, then `chartPalette`, then the default. + public var barChartPalette: [Color]? + public var horizontalBarChartPalette: [Color]? + public var lineChartPalette: [Color]? + public var areaChartPalette: [Color]? + public var pieChartPalette: [Color]? + public var radialChartPalette: [Color]? + public var radarChartPalette: [Color]? + /// Status colors (react-ui's info, success, alert and danger text): callouts, + /// tags, trends, form errors and confirmations. + public var info: Color = .blue + public var success: Color = .green + public var alert: Color = .orange + public var danger: Color = .red public init() {} @@ -59,14 +74,22 @@ extension Color { } } -/// Status colors shared by callouts, tags and form errors. -func statusColor(_ variant: String?) -> Color { - switch variant { - case "info": return .blue - case "warning": return .orange - case "error", "danger": return .red - case "success": return .green - default: return .secondary +extension OpenUITheme { + /// The color for a status variant of a callout, tag or icon. + func status(_ variant: String?) -> Color { + switch variant { + case "info": info + case "warning": alert + case "error", "danger": danger + case "success": success + default: .secondary + } + } + + /// The colors a chart picks from: its own palette, then `chartPalette` + /// (nil leaves react-ui's default ramp), like react-ui's `resolvePalette`. + func chartRamp(_ own: [Color]?) -> [Color]? { + [own, chartPalette].first { $0?.isEmpty == false } ?? nil } } diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 735b737677..34d99396a9 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -487,6 +487,31 @@ let globalTestLibrary = SwiftUILibrary( /// Mirrors react-ui's paletteUtils tests. @Suite struct ChartPaletteTests { + /// react-ui's `resolvePalette`: the chart's own palette, then the default + /// one, then the built-in ramp; an empty palette counts as none. + @Test func chartsUseTheirOwnPaletteFirst() { + var theme = OpenUITheme() + #expect(theme.chartRamp(theme.barChartPalette) == nil) + theme.chartPalette = [.red, .blue] + #expect(theme.chartRamp(theme.barChartPalette) == [.red, .blue]) + theme.barChartPalette = [.green] + #expect(theme.chartRamp(theme.barChartPalette) == [.green]) + #expect(theme.chartRamp(theme.lineChartPalette) == [.red, .blue]) + theme.barChartPalette = [] + #expect(theme.chartRamp(theme.barChartPalette) == [.red, .blue]) + } + + @Test func statusVariantsUseTheThemeColors() { + var theme = OpenUITheme() + theme.info = .cyan + theme.success = .mint + theme.alert = .yellow + theme.danger = .pink + let variants: [String?] = ["info", "success", "warning", "error", "danger", "neutral", nil] + let colors: [Color] = [.cyan, .mint, .yellow, .pink, .pink, .secondary, .secondary] + #expect(variants.map(theme.status) == colors) + } + let ramp = ChartPalette.ocean @Test func picksFromTheMiddleOutwards() { From 34534825934e71af6851e698fa54f9822eee58ad Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:42:38 +0530 Subject: [PATCH 33/52] feat(swift-lang): add react-ui's hover states for pointers With a pointer (on the Mac, or an iPad with a trackpad), controls now react the way react-ui's do: clickable cards sink a little and visual cards zoom their photo, list rows grow their marker, chips fill in, unselected option cards darken their border, empty radios and check boxes fill, inactive tabs brighten and sources highlight. A HoverButtonStyle tracks the pointer and passes it to the label through the environment, so each control draws its own hover state. Touch is unchanged. --- .../Components/CardComponents.swift | 6 +- .../Components/ContentComponents.swift | 33 +++++--- .../Components/FormComponents.swift | 18 +++- .../Components/LayoutComponents.swift | 39 +++++---- .../Components/SelectionComponents.swift | 82 ++++++++++--------- .../Sources/OpenUISwiftUI/Hover.swift | 63 ++++++++++++++ 6 files changed, 172 insertions(+), 69 deletions(-) create mode 100644 packages/swift-lang/Sources/OpenUISwiftUI/Hover.swift diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift index c1d7df56cf..69584b401a 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift @@ -215,7 +215,7 @@ private struct CardBlockLayout: View { } label: { content.contentShape(Rectangle()) } - .buttonStyle(.plain) + .buttonStyle(.openUICard) } else { content } @@ -535,6 +535,7 @@ struct VisualCardItemView: View { private struct VisualCard: View { let item: ComponentProps @Environment(\.openUICardClickable) private var clickable + @Environment(\.openUIHovered) private var hovered @Environment(\.openUITheme) private var theme var body: some View { @@ -567,6 +568,9 @@ private struct VisualCard: View { ZStack { theme.subtleSurface RemoteImage(src: item.string("bgImageSrc"), alt: item.text("bgImageAlt")) + // react-ui zooms a clickable card's photo under the pointer. + .scaleEffect(hovered ? 1.04 : 1) + .animation(.easeOut(duration: 0.3), value: hovered) } } .clipShape(RoundedRectangle(cornerRadius: 16)) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift index 74459163da..72717e3d74 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift @@ -47,22 +47,29 @@ private struct SourceCard: View { var body: some View { let url = source["url"].stringValue.flatMap(URL.init(string:)) - let card = VStack(alignment: .leading, spacing: 4) { - HStack(spacing: 8) { - Favicon(host: url?.host()) - Text(displayText(source["sourceName"])).font(.caption.weight(.medium)).lineLimit(1) + let card = Hovering { hovered in + VStack(alignment: .leading, spacing: 4) { + HStack(spacing: 8) { + Favicon(host: url?.host()) + Text(displayText(source["sourceName"])).font(.caption.weight(.medium)).lineLimit(1) + } + Text(displayText(source["title"])) + .font(.caption) + .foregroundStyle(.secondary) + .lineLimit(2) + .multilineTextAlignment(.leading) } - Text(displayText(source["title"])) - .font(.caption) - .foregroundStyle(.secondary) - .lineLimit(2) - .multilineTextAlignment(.leading) + .padding(8) + .frame(width: 180, alignment: .topLeading) + .background( + Color.primary.opacity(hovered ? 0.03 : 0), in: RoundedRectangle(cornerRadius: 10) + ) + .overlay( + RoundedRectangle(cornerRadius: 10).strokeBorder( + hovered ? theme.interactiveBorder : theme.border)) } - .padding(8) - .frame(width: 180, alignment: .topLeading) - .overlay(RoundedRectangle(cornerRadius: 10).strokeBorder(theme.border)) if let url { - Link(destination: url) { card }.buttonStyle(.plain) + Link(destination: url) { card }.buttonStyle(.openUIHover) } else { card } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift index 5d5daccd26..7c89d7cb7e 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift @@ -225,7 +225,7 @@ struct RadioGroupView: View { symbol: value == selected ? "largecircle.fill.circle" : "circle", label: item.text("label"), description: item.text("description")) } - .buttonStyle(.plain) + .buttonStyle(.openUIHover) } } .disabled(context.isStreaming) @@ -281,7 +281,7 @@ private struct BooleanGroup: View { symbol: isOn ? "checkmark.square.fill" : "square", label: item.text("label"), description: item.text("description")) } - .buttonStyle(.plain) + .buttonStyle(.openUIHover) case .toggle: // The switch leads and the text follows, as in react-ui's SwitchItem. HStack(alignment: .top, spacing: 8) { @@ -340,10 +340,22 @@ private struct OptionRow: View { let label: String let description: String @Environment(\.openUITheme) private var theme + @Environment(\.openUIHovered) private var hovered var body: some View { + let radio = symbol.contains("circle") + let empty = symbol == "circle" || symbol == "square" HStack(alignment: .firstTextBaseline, spacing: 8) { - Image(systemName: symbol).foregroundStyle(theme.accent) + Image(systemName: symbol) + .foregroundStyle(theme.accent) + // react-ui fills an empty radio or check box under the pointer. + .background { + if hovered && empty { + RoundedRectangle(cornerRadius: radio ? 10 : 3) + .fill(radio ? theme.interactiveBorder : theme.sunkSurface) + .padding(2) + } + } VStack(alignment: .leading, spacing: 2) { Text(label) if !description.isEmpty { diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift index eb9b057ab6..793eb2d2fb 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift @@ -158,15 +158,27 @@ private struct ListRow: View { @Environment(\.openUITheme) private var theme var body: some View { - let row = HStack(alignment: .top, spacing: 10) { + if let onTap { + Button(action: onTap) { Hovering(content: row) }.buttonStyle(.openUIHover) + } else { + row(hovered: false) + } + } + + /// react-ui grows a clickable row's marker and deepens its fill under the + /// pointer. + private func row(hovered: Bool) -> some View { + HStack(alignment: .top, spacing: 10) { if let marker { Text(marker) .font(.caption.weight(.semibold).monospacedDigit()) .frame(width: 22, height: 22) - .background(theme.sunkSurface, in: Circle()) + .background(hovered ? Color.primary.opacity(0.1) : theme.sunkSurface, in: Circle()) + .scaleEffect(hovered ? 1.1 : 1) } else if let src = item["image"]["src"].stringValue { RemoteImage(src: src, alt: displayText(item["image"]["alt"])) .frame(width: 44, height: 44) + .scaleEffect(hovered ? 1.1 : 1) } VStack(alignment: .leading, spacing: 2) { Text(item.text("title")).font(small ? .subheadline : .body) @@ -184,11 +196,6 @@ private struct ListRow: View { } } .contentShape(Rectangle()) - if let onTap { - Button(action: onTap) { row }.buttonStyle(.plain) - } else { - row - } } } @@ -332,15 +339,17 @@ struct TabsView: View { userChose = true withOpenUIAnimation(Motion.reveal) { active = value } } label: { - Text(item.text("trigger")) - .font(.subheadline.weight(isActive ? .semibold : .regular)) - .foregroundStyle(isActive ? .primary : .secondary) - .padding(.vertical, 6) - .overlay(alignment: .bottom) { - if isActive { Rectangle().fill(.primary).frame(height: 2) } - } + Hovering { hovered in + Text(item.text("trigger")) + .font(.subheadline.weight(isActive ? .semibold : .regular)) + .foregroundStyle(isActive || hovered ? .primary : .secondary) + .padding(.vertical, 6) + .overlay(alignment: .bottom) { + if isActive { Rectangle().fill(.primary).frame(height: 2) } + } + } } - .buttonStyle(.plain) + .buttonStyle(.openUIHover) } private func followStream(_ sizes: [(value: String, size: Int)]) { diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift index ddd85ef554..aa56077cad 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift @@ -119,22 +119,26 @@ private struct Chip: View { var body: some View { Button(action: action) { - HStack(spacing: 4) { - if let symbol = iconSymbol(item["icon"]) { Image(systemName: symbol) } - Text(item.text("label")) + Hovering { hovered in + HStack(spacing: 4) { + if let symbol = iconSymbol(item["icon"]) { Image(systemName: symbol) } + Text(item.text("label")) + } + .font(.subheadline) + .padding(.horizontal, 8) + .padding(.vertical, 6) + .background( + isOn ? Color.primary.opacity(0.08) : hovered ? theme.subtleSurface : .clear, + in: RoundedRectangle(cornerRadius: 8) + ) + .overlay( + RoundedRectangle(cornerRadius: 8).strokeBorder( + isOn ? .primary : hovered ? theme.border : theme.interactiveBorder) + ) + .contentShape(RoundedRectangle(cornerRadius: 8)) } - .font(.subheadline) - .padding(.horizontal, 8) - .padding(.vertical, 6) - .background( - isOn ? Color.primary.opacity(0.08) : .clear, in: RoundedRectangle(cornerRadius: 8) - ) - .overlay( - RoundedRectangle(cornerRadius: 8).strokeBorder(isOn ? .primary : theme.interactiveBorder) - ) - .contentShape(RoundedRectangle(cornerRadius: 8)) } - .buttonStyle(.plain) + .buttonStyle(.openUIHover) .accessibilityAddTraits(isOn ? .isSelected : []) } } @@ -163,32 +167,36 @@ private struct OptionCardTile: View { var body: some View { Button(action: action) { - VStack(alignment: .leading, spacing: 6) { - switch item["topContent"] { - case .element(let element) where element.typeName == "Icon": - Image(systemName: iconSymbol(item["topContent"]) ?? "circle") - .font(.system(size: 14)) - .frame(width: 32, height: 32) - .background(theme.sunkSurface, in: RoundedRectangle(cornerRadius: 8)) - case .element: - OpenUINode(item["topContent"]).frame(height: 90).clipped() - default: - EmptyView() - } - Text(item.text("title")).font(.subheadline.weight(.semibold)) - if let subtitle = item.string("subtitle"), !subtitle.isEmpty { - Text(subtitle).font(.caption).foregroundStyle(.secondary) + Hovering { hovered in + VStack(alignment: .leading, spacing: 6) { + switch item["topContent"] { + case .element(let element) where element.typeName == "Icon": + Image(systemName: iconSymbol(item["topContent"]) ?? "circle") + .font(.system(size: 14)) + .frame(width: 32, height: 32) + .background(theme.sunkSurface, in: RoundedRectangle(cornerRadius: 8)) + case .element: + OpenUINode(item["topContent"]).frame(height: 90).clipped() + default: + EmptyView() + } + Text(item.text("title")).font(.subheadline.weight(.semibold)) + if let subtitle = item.string("subtitle"), !subtitle.isEmpty { + Text(subtitle).font(.caption).foregroundStyle(.secondary) + } } + .padding(10) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + .background(isOn ? theme.sunkSurface : .clear, in: RoundedRectangle(cornerRadius: 14)) + .overlay( + RoundedRectangle(cornerRadius: 14).strokeBorder( + // react-ui darkens an unselected card's border under the pointer. + isOn ? .primary : hovered ? Color.primary.opacity(0.3) : theme.interactiveBorder) + ) + .contentShape(RoundedRectangle(cornerRadius: 14)) } - .padding(10) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) - .background(isOn ? theme.sunkSurface : .clear, in: RoundedRectangle(cornerRadius: 14)) - .overlay( - RoundedRectangle(cornerRadius: 14).strokeBorder(isOn ? .primary : theme.interactiveBorder) - ) - .contentShape(RoundedRectangle(cornerRadius: 14)) } - .buttonStyle(.plain) + .buttonStyle(.openUIHover) .accessibilityAddTraits(isOn ? .isSelected : []) } } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Hover.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Hover.swift new file mode 100644 index 0000000000..03fc4c2052 --- /dev/null +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Hover.swift @@ -0,0 +1,63 @@ +import SwiftUI + +private struct HoveredKey: EnvironmentKey { + static let defaultValue = false +} + +extension EnvironmentValues { + /// Whether a pointer is over the button this view is the label of (on the + /// Mac, and on iPad with a pointer; never for touch). Labels use it for + /// react-ui's hover state, which differs per control: chips fill in, option + /// cards' borders darken, list markers grow. + var openUIHovered: Bool { + get { self[HoveredKey.self] } + set { self[HoveredKey.self] = newValue } + } +} + +/// A plain button that tells its label when the pointer is over it, through +/// `openUIHovered`. With `sinks`, it's react-ui's clickable card: it sinks a +/// little under the pointer (scale 0.995) and more while pressed; otherwise it +/// dims while pressed, as the plain style does. +struct HoverButtonStyle: ButtonStyle { + var sinks = false + + func makeBody(configuration: Configuration) -> some View { + HoverLabel(configuration: configuration, sinks: sinks) + } + + private struct HoverLabel: View { + let configuration: Configuration + let sinks: Bool + @State private var hovering = false + @Environment(\.isEnabled) private var isEnabled + @Environment(\.accessibilityReduceMotion) private var reduceMotion + + var body: some View { + let hovered = hovering && isEnabled + let pressed = configuration.isPressed + configuration.label + .environment(\.openUIHovered, hovered) + .scaleEffect(sinks && !reduceMotion ? (pressed ? 0.98 : hovered ? 0.995 : 1) : 1) + .opacity(!sinks && pressed ? 0.6 : 1) + .onHover { hovering = $0 } + .animation(.easeOut(duration: 0.15), value: hovered) + .animation(.easeOut(duration: 0.1), value: pressed) + } + } +} + +extension ButtonStyle where Self == HoverButtonStyle { + /// A plain button whose label sees pointer hover (`openUIHovered`). + static var openUIHover: HoverButtonStyle { HoverButtonStyle() } + /// react-ui's clickable card: sinks a little under the pointer. + static var openUICard: HoverButtonStyle { HoverButtonStyle(sinks: true) } +} + +/// Reads `openUIHovered` for a label built inline in a button. +struct Hovering: View { + @ViewBuilder let content: (Bool) -> Content + @Environment(\.openUIHovered) private var hovered + + var body: some View { content(hovered) } +} From f94bebb8c14d1ce3157297847e42ad4aa7afac9b Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:45:21 +0530 Subject: [PATCH 34/52] docs(swift-lang): list the deliberate differences from react-ui The section on differences covered lang-core and a few rendering limits. It now also covers the choices made for native platforms: tooltips on a tap without hover, editable table cells that stay text fields, and the gallery's fixed mosaic proportions. --- packages/swift-lang/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/swift-lang/README.md b/packages/swift-lang/README.md index 417a35b468..cd83537f80 100644 --- a/packages/swift-lang/README.md +++ b/packages/swift-lang/README.md @@ -237,13 +237,16 @@ Conform your own type to `ToolProvider` for other backends. `library.toJSONSchema()` produces the same document as `library.toJSONSchema()` in `lang-core` (component schemas under `$defs`, props in positional order), and the parser compiles positional parameters from it. When reading a schema from JSON, use `JSON.parse(_:)`, which keeps object key order. -## Differences from lang-core +## Differences from the JavaScript packages - A component inside `@Each` or a ternary that binds a reactive prop to `$state` writes the typed value. In `lang-core` that binding is re-evaluated and nested, so typing writes `undefined`. - Composite values (arrays, objects) have no identity in Swift, so `==` between two of them is always false. In JavaScript it's true only for the same instance. - Prop evaluation and SwiftUI views can't throw, so `onError` never reports `runtime-error` or `render-error`. - `$$` math in text content shows as source; there's no native TeX renderer. - Code is highlighted with Prism's `vscDarkPlus` and `oneLight` colors by a small built-in tokenizer covering common languages (C-family, JSON, markup, Python, Ruby, shell, YAML, SQL), not by Prism's grammars. +- Touch has no hover, so a chart's tooltip opens on a tap and stays until the same spot is tapped again (or another chart's opens), where react-ui shows it while a finger moves. Hover states need a pointer: the Mac, or an iPad with a trackpad. +- Editable table cells are always text fields, which suits touch, rather than react-ui's select-then-edit cells. With a keyboard, Up and Down move between rows and Enter moves down; Escape doesn't undo an edit. +- The image gallery's mosaic has fixed proportions instead of taking its height from the loaded images, so it doesn't jump when they arrive, and the viewer shows each image's `details`. - Not ported: `jsonToOpenUI`, the deprecated `enrichErrors` (its hints are in `onError`), and the server-side `artifactTool` from `@openuidev/lang-core/cloud`. ## Testing Locally From 478c2062904bdc1d1a58d0af31dca02e78641a29 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 18:27:05 +0530 Subject: [PATCH 35/52] fix(swift-lang): word tool errors like lang-core's err.message Query and Mutation errors interpolated the thrown error, which for a Cocoa error prints its debug form: a location lookup that hadn't got a fix yet reported "Error Domain=kCLErrorDomain Code=0 "(null)"" to onError and to the user. They now use what lang-core's err.message corresponds to: a LocalizedError's description, a Cocoa error's localized description, and otherwise the error's own description as before. --- .../Sources/OpenUILang/QueryManager.swift | 20 +++++++++++--- .../OpenUILangTests/QueryAndFormTests.swift | 27 +++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUILang/QueryManager.swift b/packages/swift-lang/Sources/OpenUILang/QueryManager.swift index cf8764c258..17e3052d6d 100644 --- a/packages/swift-lang/Sources/OpenUILang/QueryManager.swift +++ b/packages/swift-lang/Sources/OpenUILang/QueryManager.swift @@ -1,3 +1,5 @@ +import Foundation + /// Calls the tools behind `Query(...)` and `Mutation(...)` statements: MCP, /// REST, GraphQL or anything else. public protocol ToolProvider: Sendable { @@ -52,6 +54,16 @@ public func extractToolResult(_ result: OpenUIValue) throws -> OpenUIValue { return .null } +/// A thrown error's message, as lang-core reads `err.message`: a +/// `LocalizedError`'s description, a Cocoa error's localized description +/// (its debug form reads `Error Domain=… Code=0 "(null)"`), or the error as +/// text, which for this package's errors is their description. +func errorMessage(_ error: Error) -> String { + if let description = (error as? LocalizedError)?.errorDescription { return description } + if type(of: error) is NSError.Type { return (error as NSError).localizedDescription } + return "\(error)" +} + /// A tool provider backed by a map of async handlers. public struct FunctionToolProvider: ToolProvider { public typealias Handler = @Sendable (OpenUIObject) async throws -> OpenUIValue @@ -308,7 +320,8 @@ public final class QueryManager { statementId: statementId, component: "Query", toolName: toolName) } return OpenUIError( - source: .query, code: "tool-error", message: "Query \"\(toolName)\" failed: \(error)", + source: .query, code: "tool-error", + message: "Query \"\(toolName)\" failed: \(errorMessage(error))", statementId: statementId, component: "Query", toolName: toolName) } @@ -445,7 +458,7 @@ public final class QueryManager { success = true } catch { if disposed || currentGeneration != generation { return false } - mutations[statementId]?.result = ["status": "error", "error": .string("\(error)")] + mutations[statementId]?.result = ["status": "error", "error": .string(errorMessage(error))] mutations[statementId]?.error = mutationError( error, toolName: mutation.toolName, statementId: statementId) } @@ -471,7 +484,8 @@ public final class QueryManager { statementId: statementId, component: "Mutation", toolName: toolName) } return OpenUIError( - source: .mutation, code: "tool-error", message: "Mutation \"\(toolName)\" failed: \(error)", + source: .mutation, code: "tool-error", + message: "Mutation \"\(toolName)\" failed: \(errorMessage(error))", statementId: statementId, component: "Mutation", toolName: toolName) } diff --git a/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift b/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift index c641491b8b..ff99595149 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift +++ b/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift @@ -1,3 +1,4 @@ +import Foundation import Testing @testable import OpenUILang @@ -89,6 +90,32 @@ import Testing #expect(manager.snapshot.errors.first?.code == "mcp-error") } + /// Errors read like lang-core's `err.message`: a Cocoa error's localized + /// description rather than its `Error Domain=… Code=0 "(null)"` debug form, + /// and a `LocalizedError`'s own description. + @Test func toolErrorsUseTheErrorsMessage() async { + struct Offline: LocalizedError { + var errorDescription: String? { "You're offline." } + } + let cocoa = NSError(domain: "kCLErrorDomain", code: 0) + let provider = FunctionToolProvider([ + "locate": { _ in throw cocoa }, + "sync": { _ in throw Offline() }, + ]) + let manager = QueryManager(toolProvider: provider) + manager.registerMutations([ + MutationNode(statementId: "locate", toolName: "locate"), + MutationNode(statementId: "sync", toolName: "sync"), + ]) + _ = await manager.fireMutation("locate", args: [:]) + _ = await manager.fireMutation("sync", args: [:]) + let messages = manager.snapshot.errors.map(\.message) + #expect(messages.contains("Mutation \"locate\" failed: \(cocoa.localizedDescription)")) + #expect(messages.contains("Mutation \"sync\" failed: You're offline.")) + #expect(!messages.joined().contains("Error Domain")) + #expect(manager.mutationResult("sync")?["error"] == "You're offline.") + } + @Test func failedMutationHaltsTheActionPlan() async { let provider = FunctionToolProvider(["fail": { _ in throw ToolNotFoundError(toolName: "x") }]) let runtime = OpenUIRuntime(library: FixtureLibrary(schemaName: "test"), toolProvider: provider) From d668047961d31ba0705e9601e6f10175a7f461cf Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 18:27:05 +0530 Subject: [PATCH 36/52] fix(swift-lang): keep card block cards readable on narrow screens With responsive set to false, react-ui keeps up to three cards per row and lets each card's minimum width (196px for context cards, 158px for overview cards, 15rem for composite cards) overflow its column. The port had no minimum, so on a phone three context cards squeezed to a word or two per line with hyphens. The grid now drops to as many columns as fit at the card's minimum width, keeping react-ui's breakpoints otherwise. --- .../Components/CardComponents.swift | 44 +++++++++++++------ .../OpenUISwiftUITests/RendererTests.swift | 26 +++++++++++ 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift index 69584b401a..8933f02898 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift @@ -84,10 +84,13 @@ struct ResponsiveCardGrid: View { let maxPerRow: Int var responsive = true var spacing: CGFloat = 12 + var minCellWidth: CGFloat = 0 @ViewBuilder let cell: (Int) -> Cell var body: some View { - CardGridLayout(maxPerRow: maxPerRow, responsive: responsive, spacing: spacing) { + CardGridLayout( + maxPerRow: maxPerRow, responsive: responsive, spacing: spacing, minCellWidth: minCellWidth + ) { ForEach(0.. CGSize { guard let width = proposal.width, width.isFinite else { @@ -145,16 +152,25 @@ struct CardGridLayout: Layout { private func rowCount(_ count: Int, _ width: CGFloat) -> Int { rows(count, width).count } + /// The most cards per row: react-ui's breakpoints, then as many as fit at + /// `minCellWidth`. + static func columns( + width: CGFloat, maxPerRow: Int, responsive: Bool, spacing: CGFloat, minCellWidth: CGFloat + ) -> Int { + let breakpoint = !responsive ? maxPerRow : width <= 480 ? 1 : width <= 768 ? 2 : maxPerRow + guard minCellWidth > 0 else { return breakpoint } + let fitting = Int((width + spacing) / (minCellWidth + spacing)) + return max(1, min(breakpoint, fitting)) + } + /// Subview indices per row, using react-ui's breakpoints. private func rows(_ count: Int, _ width: CGFloat) -> [[Int]] { - let perRow: [Int] - if responsive && width <= 480 { - perRow = Array(repeating: 1, count: count) - } else if responsive && width <= 768 { - perRow = cardRowConfiguration(count, maxPerRow: 2) - } else { - perRow = cardRowConfiguration(count, maxPerRow: maxPerRow) - } + let columns = Self.columns( + width: width, maxPerRow: maxPerRow, responsive: responsive, spacing: spacing, + minCellWidth: minCellWidth) + let perRow = + columns == 1 + ? Array(repeating: 1, count: count) : cardRowConfiguration(count, maxPerRow: columns) var start = 0 return perRow.map { length in defer { start += length } @@ -172,6 +188,8 @@ private struct CardBlockLayout: View { let props: ComponentProps let size: CardBlockSize let maxPerRow: Int + /// The card's minimum width in react-ui's styles, if it has one. + var minCardWidth: CGFloat = 0 let click: (Int, ComponentProps) -> (label: String, context: OpenUIObject) @ViewBuilder let item: (ComponentProps) -> Item @Environment(OpenUIContext.self) private var context @@ -195,7 +213,7 @@ private struct CardBlockLayout: View { } else { ResponsiveCardGrid( count: items.count, maxPerRow: maxPerRow, responsive: props.bool("responsive") != false, - spacing: gap + spacing: gap, minCellWidth: minCardWidth ) { index in card(index, items[index], clickable: clickable) } @@ -312,7 +330,7 @@ private struct SnippetCard: View { struct OverviewCardBlockView: View { let props: ComponentProps var body: some View { - CardBlockLayout(props: props, size: .small, maxPerRow: 3) { index, item in + CardBlockLayout(props: props, size: .small, maxPerRow: 3, minCardWidth: 158) { index, item in let title = childString(item["top"], "title") ?? childString(item["top"], "value") let subtitle = childString(item["top"], "subtitle") ?? childString(item["top"], "subtext") return ( @@ -359,7 +377,7 @@ private struct OverviewCard: View { struct ContextCardBlockView: View { let props: ComponentProps var body: some View { - CardBlockLayout(props: props, size: .small, maxPerRow: 3) { index, item in + CardBlockLayout(props: props, size: .small, maxPerRow: 3, minCardWidth: 196) { index, item in let title = contextTitle(item) return ( title.isEmpty ? (item.string("id") ?? "Context card \(index + 1)") : title, @@ -441,7 +459,7 @@ private struct ContextCard: View { struct CompositeCardBlockView: View { let props: ComponentProps var body: some View { - CardBlockLayout(props: props, size: .medium, maxPerRow: 2) { index, item in + CardBlockLayout(props: props, size: .medium, maxPerRow: 2, minCardWidth: 240) { index, item in let header = item["header"].elementValue?.props ?? OpenUIObject() func pick(_ keys: String...) -> String? { keys.lazy.compactMap { header[$0]?.stringValue }.first diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 34d99396a9..bdd215ee9d 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -844,3 +844,29 @@ let globalTestLibrary = SwiftUILibrary( #expect(edits["1", 0] == nil) } } + +/// Card grids keep react-ui's breakpoints but never squeeze a card below its +/// react-ui minimum width. +@Suite struct CardGridColumnsTests { + func columns(_ width: CGFloat, responsive: Bool, min: CGFloat = 0) -> Int { + CardGridLayout.columns( + width: width, maxPerRow: 3, responsive: responsive, spacing: 12, minCellWidth: min) + } + + @Test func followsReactUIBreakpoints() { + #expect(columns(400, responsive: true) == 1) + #expect(columns(700, responsive: true) == 2) + #expect(columns(900, responsive: true) == 3) + #expect(columns(400, responsive: false) == 3) + } + + /// A context card (196pt minimum) in a non-responsive block on a phone: one + /// per row instead of three a word wide. + @Test func dropsColumnsBelowTheCardsMinimum() { + #expect(columns(350, responsive: false, min: 196) == 1) + #expect(columns(404, responsive: false, min: 196) == 2) + #expect(columns(612, responsive: false, min: 196) == 3) + #expect(columns(900, responsive: true, min: 196) == 3) + #expect(columns(10, responsive: false, min: 196) == 1) + } +} From 17b40d172bbde6cf19e0c4c6bf4fb82be81ec958 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 18:27:05 +0530 Subject: [PATCH 37/52] fix(swift-lang): keep primary buttons readable when gray Primary buttons set their label to the theme's onAccent color. The system draws a disabled prominent button, and every prominent button in an inactive Mac window, gray instead of in the accent, which left white text on light gray. Those now keep the system's label color. --- .../Components/FormComponents.swift | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift index 7c89d7cb7e..c3d0e4b60a 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift @@ -801,9 +801,23 @@ private struct ButtonVariant: ViewModifier { /// A filled button in the theme's accent, with its `onAccent` label. struct ProminentButton: ViewModifier { @Environment(\.openUITheme) private var theme + @Environment(\.isEnabled) private var isEnabled + #if os(macOS) + @Environment(\.controlActiveState) private var activeState + #endif func body(content: Content) -> some View { - content.buttonStyle(.borderedProminent).foregroundStyle(theme.onAccent) + content.buttonStyle(.borderedProminent).foregroundStyle(labelColor) + } + + /// The system draws a disabled button, or any prominent button in an + /// inactive Mac window, gray instead of in the accent. The accent's label + /// color would be unreadable on that, so those keep the system's. + private var labelColor: Color { + #if os(macOS) + if activeState == .inactive { return .primary } + #endif + return isEnabled ? theme.onAccent : .secondary } } From bb2ef3ed7bbec3014c4270153052502f67b3f5ef Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 18:38:06 +0530 Subject: [PATCH 38/52] fix(swift-lang): give each node its full height in fixed-height layouts Offered exactly its ideal height (a fixed frame, a self-sizing table cell), a response's VStack split that height by flexibility. A row with a Spacer (a list item, callout, check box or key/value row) counts as very flexible, so wrapping text above it was offered too little and cut off mid-sentence, and the leftover height stayed empty. Each node now takes its ideal height for its width. In a scroll view, which offers unlimited height, nothing changes. --- .../Sources/OpenUISwiftUI/OpenUINode.swift | 8 ++++- .../OpenUISwiftUITests/RendererTests.swift | 34 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUINode.swift b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUINode.swift index d15106eb8e..2b0c64e79c 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/OpenUINode.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/OpenUINode.swift @@ -44,7 +44,13 @@ public struct OpenUINodes: View { public var body: some View { VStack(alignment: alignment, spacing: spacing) { ForEach(items) { item in - OpenUINode(item.value).transition(.openUIInsertion) + OpenUINode(item.value) + // Each node is as tall as it needs to be at this width. Offered + // exactly the stack's ideal height (a fixed frame, a self-sizing + // cell), a VStack splits it by flexibility instead, so wrapping text + // next to a row with a Spacer is cut short and space is left over. + .fixedSize(horizontal: false, vertical: true) + .transition(.openUIInsertion) } } // Nodes keep their identity, so only newly streamed ones animate in. diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index bdd215ee9d..3009cf7945 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -192,6 +192,40 @@ import Testing #expect(errors.allSatisfy { $0.jsonRepresentation["source"] == "parser" }, "\(errors)") } + /// Offered exactly its ideal height (a fixed frame, a self-sizing cell), + /// a response lays out at that height. A VStack split the height by + /// flexibility instead, cutting wrapping text short next to a row with a + /// Spacer and leaving the rest of the height empty. + @Test func fillsExactlyItsIdealHeight() { + final class Box { var height: CGFloat = 0 } + let response = """ + root = Card([intro, tip]) + intro = TextContent("That is **Bangalore Palace** in Bengaluru, Karnataka! Built in 1878, its Tudor-style architecture was inspired by Windsor Castle, with fortified towers, battlements and lush gardens.") + tip = Callout("info", "Good to know", "Sprawling gardens used for cultural exhibitions, concerts, flower shows and public events across the year.") + """ + let measured = NSHostingView( + rootView: OpenUIRenderer(response: response, library: OpenUIChatLibrary.library) + .frame(width: 340)) + RunLoop.main.run(until: Date().addingTimeInterval(0.2)) + let ideal = measured.fittingSize.height + let box = Box() + let host = NSHostingView( + rootView: OpenUIRenderer(response: response, library: OpenUIChatLibrary.library) + .onGeometryChange(for: CGFloat.self) { + $0.size.height + } action: { + box.height = $0 + } + .frame(width: 340, height: ideal)) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 340, height: ideal), styleMask: [.borderless], + backing: .buffered, defer: false) + window.contentView = host + RunLoop.main.run(until: Date().addingTimeInterval(0.3)) + #expect(ideal > 100) + #expect(abs(box.height - ideal) < 1, "laid out \(box.height) of \(ideal)") + } + /// A closed Modal takes no room in a Stack, gap included, as in react-ui /// where it renders nothing. @Test func closedModalTakesNoRoom() { From 54e15a69458ba99cea1dc90efc62ad12a274856a Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 18:53:54 +0530 Subject: [PATCH 39/52] fix(swift-lang): let horizontal bar charts grow to fit their bars A horizontal bar chart needs a row per category, so it asked for at least 28pt each, but its frame was fixed at the chart height. With more than about eight categories the bars overflowed the frame above and below, over the axis titles and the value labels. The frame now grows to the chart's minimum instead. --- .../Components/ChartComponents.swift | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift index 46bb1e714c..ef8147757d 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift @@ -148,23 +148,27 @@ private struct ChartFrame: View { let isEmpty: Bool let legend: [LegendEntry] let hidden: Binding>? + /// The least height the chart needs, e.g. a row per bar. + let minHeight: CGFloat let content: Content @Environment(OpenUIContext.self) private var context @Environment(\.openUITheme) private var theme init( _ props: ComponentProps, isEmpty: Bool, legend: [LegendEntry], - hidden: Binding>? = nil, @ViewBuilder content: () -> Content + hidden: Binding>? = nil, minHeight: CGFloat = 0, + @ViewBuilder content: () -> Content ) { self.props = props self.isEmpty = isEmpty self.legend = legend self.hidden = hidden + self.minHeight = minHeight self.content = content() } var body: some View { - let height = props.number("height").map { CGFloat($0) } ?? theme.chartHeight + let height = max(props.number("height").map { CGFloat($0) } ?? theme.chartHeight, minHeight) if isEmpty && (context.isStreaming || context.isQueryLoading) { SkeletonBlock(height: height, cornerRadius: 8) } else { @@ -261,7 +265,12 @@ struct HorizontalBarChartView: View { let series = SeriesColors(seriesNames(props), theme.chartRamp(theme.horizontalBarChartPalette)) let stacked = props.string("variant") == "stacked" let labels = labelOrder(props) - ChartFrame(props, isEmpty: all.isEmpty, legend: series.legend, hidden: $hidden) { + // A row per bar, at least 28pt each: past that the frame grows instead of + // the bars spilling over the axis titles. + ChartFrame( + props, isEmpty: all.isEmpty, legend: series.legend, hidden: $hidden, + minHeight: CGFloat(labels.count) * 28 + ) { Chart(points) { point in if stacked { BarMark( @@ -285,7 +294,6 @@ struct HorizontalBarChartView: View { } } .valueAxis(.horizontal) - .frame(minHeight: CGFloat(labels.count) * 28) .categoryPicker( $selection, axis: .vertical, crosshairBehind: true, tooltip: { seriesTooltip($0, points, series) } From 663e3b62a7b3ae45ccd396239fd4f20dc9f2ab6b Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 18:54:03 +0530 Subject: [PATCH 40/52] fix(swift-lang): thin crowded chart axis labels like react-ui MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bar, line and area charts squeezed every category label into its own slot, so on a phone eight city names read "Mum…", "Kolk…" and a burndown's "Sprint 1" to "Sprint 10" all read "Sprin…". react-ui's condensed axis draws every n-th label once a category is narrower than its label (counting at most 40px) plus an 8px gap, and gives each the room of the ones skipped. The port now does the same: each label is centered under its category, and the first and last are cut at the ends of the plot and moved inside it, as react-ui's CondensedXAxis keeps them. --- .../Components/ChartComponents.swift | 104 ++++++++++++++++-- .../Components/ChartInteraction.swift | 6 +- .../OpenUISwiftUITests/RendererTests.swift | 36 ++++++ 3 files changed, 133 insertions(+), 13 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift index ef8147757d..a483f52e1a 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift @@ -117,13 +117,10 @@ private func seriesTooltip( extension View { /// Horizontal grid lines only, as react-ui's cartesian charts draw them. - fileprivate func categoryAxisWithoutGrid() -> some View { - chartXAxis { - AxisMarks { _ in - AxisTick() - AxisValueLabel() - } - } + /// The category axis: ticks, no grid lines, and react-ui's condensed + /// labels (see `CategoryLabels`). + fileprivate func categoryAxisWithoutGrid(_ labels: [String]) -> some View { + modifier(CategoryAxis(labels: labels)) } /// react-ui's value axis: on the leading side, with grid lines and its tick @@ -141,6 +138,93 @@ extension View { } } +/// react-ui's condensed x-axis labels (`layoutXAxisLabels`): every category +/// shares the width, so when one is narrower than its label (counting at most +/// 40pt of it) plus an 8pt gap, only every n-th label is drawn, each truncated +/// to the room it then has. Without this, every label truncates to a letter or +/// two ("Mum…", "Kolk…") and similar ones ("Sprint 1", "Sprint 2") all read +/// the same. +enum CategoryLabels { + static let gap: CGFloat = 8 + static let minWidth: CGFloat = 40 + + /// Draw every `interval`-th label, each up to `width` wide. + static func layout(widest: CGFloat, slot: CGFloat, count: Int) -> (interval: Int, width: CGFloat) + { + guard slot > 0, count > 0 else { return (1, slot) } + let needed = min(widest, minWidth) + gap + let interval = min(count, max(1, Int((needed / slot).rounded(.up)))) + return (interval, slot * CGFloat(interval) - gap) + } + + /// Where a label goes, as react-ui's CondensedXAxis draws it: in a box + /// `width` wide centered on its category, cut at the ends of the plot, with + /// the text truncated to the box and moved inside it. Returns the text's + /// width and its offset from the category's center. + static func place( + text: CGFloat, center: CGFloat, width: CGFloat, plot: CGFloat + ) -> (width: CGFloat, offset: CGFloat) { + let left = max(0, center - width / 2) + let right = min(plot, center + width / 2) + let shown = min(text, max(right - left, 0)) + let x = min(max(center, left + shown / 2), right - shown / 2) + return (shown, x - center) + } +} + +private struct CategoryAxis: ViewModifier { + let labels: [String] + @State private var width: CGFloat = 0 + @State private var plotWidth: CGFloat = 0 + + func body(content: Content) -> some View { + // Until the plot is measured, it's the chart less its value axis, about + // 36pt of labels. + let plot = plotWidth > 0 ? plotWidth : max(width - 36, 0) + let slot = labels.isEmpty ? 0 : plot / CGFloat(labels.count) + let widest = labels.map { ChartLegend.textWidth($0, style: .caption2) }.max() ?? 0 + let (interval, labelWidth) = CategoryLabels.layout( + widest: widest, slot: slot, count: labels.count) + let shown = labels.enumerated().filter { $0.offset % interval == 0 }.map(\.element) + content + .chartXAxis { + AxisMarks(values: width > 0 ? shown : labels) { value in + AxisTick() + // Swift Charts would fit each label to one category's width and + // center it there even past the ends of the chart. Each label gets + // the room left by the labels skipped instead, kept inside the plot. + AxisValueLabel(collisionResolution: .disabled) { + if let label = value.as(String.self) { + let text = ChartLegend.textWidth(label, style: .caption2) + 2 + let center = slot * (CGFloat(labels.firstIndex(of: label) ?? 0) + 0.5) + let (size, offset) = + width > 0 + ? CategoryLabels.place(text: text, center: center, width: labelWidth, plot: plot) + : (text, 0) + Text(label) + .lineLimit(1) + .frame(width: size) + .fixedSize() + .offset(x: offset) + } + } + } + } + .chartPlotStyle { area in + area.onGeometryChange(for: CGFloat.self) { + $0.size.width + } action: { + plotWidth = $0 + } + } + .onGeometryChange(for: CGFloat.self) { + $0.size.width + } action: { + width = $0 + } + } +} + /// Sizes a chart and puts react-ui's legend under it, or shows a pulsing /// placeholder while the response streams in before any of its values have. private struct ChartFrame: View { @@ -238,7 +322,7 @@ struct BarChartView: View { } .chartXScale(domain: labels) .chartForegroundStyleScale(domain: series.names, range: series.colors) - .categoryAxisWithoutGrid() + .categoryAxisWithoutGrid(labelOrder(props)) .valueAxis() .categoryPicker( $selection, crosshairBehind: true, tooltip: { seriesTooltip($0, points, series) } @@ -330,7 +414,7 @@ struct LineChartView: View { } .chartXScale(domain: labelOrder(props)) .chartForegroundStyleScale(domain: series.names, range: series.colors) - .categoryAxisWithoutGrid() + .categoryAxisWithoutGrid(labelOrder(props)) .valueAxis() .categoryPicker($selection, tooltip: { seriesTooltip($0, points, series) }) { proxy, plot, label in @@ -387,7 +471,7 @@ struct AreaChartView: View { } .chartXScale(domain: labelOrder(props)) .chartForegroundStyleScale(domain: series.names, range: series.colors) - .categoryAxisWithoutGrid() + .categoryAxisWithoutGrid(labelOrder(props)) .valueAxis() .categoryPicker($selection, tooltip: { seriesTooltip($0, points, series) }) { proxy, plot, label in diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartInteraction.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartInteraction.swift index 02d654b8c1..ed565a5f10 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartInteraction.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartInteraction.swift @@ -187,11 +187,11 @@ struct ChartLegend: View { textWidth("\(count) more") + 20 } - private static func textWidth(_ text: String) -> CGFloat { + static func textWidth(_ text: String, style: Font.TextStyle = .caption) -> CGFloat { #if os(macOS) - let font = NSFont.preferredFont(forTextStyle: .caption1) + let font = NSFont.preferredFont(forTextStyle: style == .caption2 ? .caption2 : .caption1) #else - let font = UIFont.preferredFont(forTextStyle: .caption1) + let font = UIFont.preferredFont(forTextStyle: style == .caption2 ? .caption2 : .caption1) #endif return ceil((text as NSString).size(withAttributes: [.font: font]).width) } diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 3009cf7945..7b519693b8 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -904,3 +904,39 @@ let globalTestLibrary = SwiftUILibrary( #expect(columns(10, responsive: false, min: 196) == 1) } } + +/// react-ui's condensed x-axis labels: crowded categories label every n-th +/// one, each truncated to the room it then has. +@Suite struct CategoryLabelsTests { + @Test func labelsEveryCategoryWhenTheyFit() { + let layout = CategoryLabels.layout(widest: 30, slot: 40, count: 6) + #expect(layout.interval == 1) + #expect(layout.width == 32) + } + + /// Eight cities on a phone: every second one, with room for "Mumbai". + @Test func thinsCrowdedLabels() { + let layout = CategoryLabels.layout(widest: 70, slot: 40, count: 8) + #expect(layout.interval == 2) + #expect(layout.width == 72) + // Only up to 40pt of a long label counts, as in react-ui. + #expect(CategoryLabels.layout(widest: 300, slot: 10, count: 20).interval == 5) + } + + @Test func neverSkipsPastTheLastCategory() { + #expect(CategoryLabels.layout(widest: 100, slot: 2, count: 3).interval == 3) + #expect(CategoryLabels.layout(widest: 100, slot: 0, count: 3).interval == 1) + } + + /// Labels center on their category and stay inside the plot, as react-ui's + /// CondensedXAxis keeps them. + @Test func keepsLabelsInsideThePlot() { + // In the middle: centered, truncated to its box when it's too long. + #expect(CategoryLabels.place(text: 30, center: 100, width: 72, plot: 300) == (30, 0)) + #expect(CategoryLabels.place(text: 100, center: 150, width: 72, plot: 300) == (72, 0)) + // The first label's box is cut at the start, and the label moves in. + #expect(CategoryLabels.place(text: 60, center: 20, width: 72, plot: 300) == (56, 8)) + // The last one is cut at the end and moves back. + #expect(CategoryLabels.place(text: 50, center: 290, width: 72, plot: 300) == (46, -13)) + } +} From 20feb8b61e2da001aa0b5e0d245d925251bc6ddb Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 19:01:02 +0530 Subject: [PATCH 41/52] fix(swift-lang): thin axis labels until they fit instead of cutting them off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit react-ui's rule only thins labels until each has 40px, so longer ones still truncate: a cohort chart's seven "Month n" labels read "Month…". The axis now keeps thinning while labels would be cut off, as long as three remain, and draws them in the font they're measured in, which also stops labels that fit from being truncated. The README lists this with the other differences from react-ui. --- packages/swift-lang/README.md | 1 + .../Components/ChartComponents.swift | 10 ++++++++-- .../Tests/OpenUISwiftUITests/RendererTests.swift | 15 +++++++++++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/swift-lang/README.md b/packages/swift-lang/README.md index cd83537f80..7c73bd6cbc 100644 --- a/packages/swift-lang/README.md +++ b/packages/swift-lang/README.md @@ -246,6 +246,7 @@ Conform your own type to `ToolProvider` for other backends. - Code is highlighted with Prism's `vscDarkPlus` and `oneLight` colors by a small built-in tokenizer covering common languages (C-family, JSON, markup, Python, Ruby, shell, YAML, SQL), not by Prism's grammars. - Touch has no hover, so a chart's tooltip opens on a tap and stays until the same spot is tapped again (or another chart's opens), where react-ui shows it while a finger moves. Hover states need a pointer: the Mac, or an iPad with a trackpad. - Editable table cells are always text fields, which suits touch, rather than react-ui's select-then-edit cells. With a keyboard, Up and Down move between rows and Enter moves down; Escape doesn't undo an edit. +- Crowded chart axes keep thinning their labels until the longest fits, down to three labels. react-ui stops thinning once each label has 40px and truncates the rest. - The image gallery's mosaic has fixed proportions instead of taking its height from the loaded images, so it doesn't jump when they arrive, and the viewer shows each image's `details`. - Not ported: `jsonToOpenUI`, the deprecated `enrichErrors` (its hints are in `onError`), and the server-side `artifactTool` from `@openuidev/lang-core/cloud`. diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift index a483f52e1a..9af572ba9c 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift @@ -148,12 +148,17 @@ enum CategoryLabels { static let gap: CGFloat = 8 static let minWidth: CGFloat = 40 - /// Draw every `interval`-th label, each up to `width` wide. + /// Draw every `interval`-th label, each up to `width` wide. Past react-ui's + /// rule, it thins further while labels would still be cut off, as long as + /// at least three stay: "Month 0, Month 2, Month 4" reads better than seven + /// "Month…". static func layout(widest: CGFloat, slot: CGFloat, count: Int) -> (interval: Int, width: CGFloat) { guard slot > 0, count > 0 else { return (1, slot) } let needed = min(widest, minWidth) + gap - let interval = min(count, max(1, Int((needed / slot).rounded(.up)))) + var interval = min(count, max(1, Int((needed / slot).rounded(.up)))) + let sparsest = max(interval, (count + 2) / 3) + while slot * CGFloat(interval) - gap < widest, interval < sparsest { interval += 1 } return (interval, slot * CGFloat(interval) - gap) } @@ -202,6 +207,7 @@ private struct CategoryAxis: ViewModifier { ? CategoryLabels.place(text: text, center: center, width: labelWidth, plot: plot) : (text, 0) Text(label) + .font(.caption2) .lineLimit(1) .frame(width: size) .fixedSize() diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 7b519693b8..f0167c2b05 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -919,8 +919,19 @@ let globalTestLibrary = SwiftUILibrary( let layout = CategoryLabels.layout(widest: 70, slot: 40, count: 8) #expect(layout.interval == 2) #expect(layout.width == 72) - // Only up to 40pt of a long label counts, as in react-ui. - #expect(CategoryLabels.layout(widest: 300, slot: 10, count: 20).interval == 5) + // react-ui's rule alone when the labels then fit: 48pt needed in 10pt slots. + #expect(CategoryLabels.layout(widest: 40, slot: 10, count: 20).interval == 5) + } + + /// Past react-ui's rule: thinning further beats cutting every label off, + /// down to three labels. + @Test func thinsRatherThanTruncates() { + // Seven "Month n" labels, 48pt wide, in 53pt slots: every second one. + let months = CategoryLabels.layout(widest: 48, slot: 53, count: 7) + #expect(months.interval == 2) + #expect(months.width >= 48) + // Labels too long for any thinning keep at least three. + #expect(CategoryLabels.layout(widest: 500, slot: 40, count: 9).interval == 3) } @Test func neverSkipsPastTheLastCategory() { From 2485549ebc25db1d8d203de33e4156ec9a388cf4 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:44:56 +0530 Subject: [PATCH 42/52] fix(swift-lang): keep numbers a layout can't use from crashing views Numbers in a response can be infinite or NaN (1e999, 0/0) or far larger than a view can draw, and a few of them reached conversions that trap or loops that never end: a Query refresh interval of 1e999, a TextArea with 1e999 rows and a discrete Slider up to 1e999 crashed; a discrete Slider with a billion steps hung, building its menu options, and on the Mac laying out a tick mark per step. Bounds and sizes that aren't finite now fall back to their defaults, refresh intervals stop at setInterval's longest delay, step menus give up past 200 options without building them, and a slider with more than 100 steps snaps its own value. --- .../Sources/OpenUILang/QueryManager.swift | 5 +- .../OpenUISwiftUI/ComponentProps.swift | 6 ++ .../Components/CardComponents.swift | 4 +- .../Components/ChartComponents.swift | 15 ++++- .../Components/FormComponents.swift | 57 ++++++++++++------- .../Components/SelectionComponents.swift | 3 +- .../OpenUILangTests/QueryAndFormTests.swift | 16 ++++++ .../OpenUISwiftUITests/RendererTests.swift | 40 +++++++++++++ 8 files changed, 119 insertions(+), 27 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUILang/QueryManager.swift b/packages/swift-lang/Sources/OpenUILang/QueryManager.swift index 17e3052d6d..f7b05d592a 100644 --- a/packages/swift-lang/Sources/OpenUILang/QueryManager.swift +++ b/packages/swift-lang/Sources/OpenUILang/QueryManager.swift @@ -370,9 +370,12 @@ public final class QueryManager { queries[node.statementId]?.timer = nil if interval > 0 { let statementId = node.statementId + // At most setInterval's longest delay (2³¹−1 ms): the interval comes + // from the response, and an infinite one can't be slept for. + let nanoseconds = UInt64(min(interval, 2_147_483.647) * 1_000_000_000) queries[node.statementId]?.timer = Task { [weak self] in while !Task.isCancelled { - try? await Task.sleep(nanoseconds: UInt64(interval * 1_000_000_000)) + try? await Task.sleep(nanoseconds: nanoseconds) guard let self, !Task.isCancelled, !self.disposed, self.toolProvider != nil, let current = self.queries[statementId] else { return } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/ComponentProps.swift b/packages/swift-lang/Sources/OpenUISwiftUI/ComponentProps.swift index bb4b4220cb..c586c9e87e 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/ComponentProps.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/ComponentProps.swift @@ -53,3 +53,9 @@ public func displayText(_ value: OpenUIValue) -> String { default: return "" } } + +extension Double { + /// The number, or nil when it's infinite or NaN. Numbers in a response can + /// be either (1e999, 0/0), and as sizes or ranges they'd break the layout. + var finite: Double? { isFinite ? self : nil } +} diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift index 8933f02898..fc5a9238be 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift @@ -197,7 +197,7 @@ private struct CardBlockLayout: View { var body: some View { let items = props.children("items") - let gap = props.number("gap").map { CGFloat($0) } ?? 12 + let gap = props.number("gap").flatMap(\.finite).map { CGFloat(max($0, 0)) } ?? 12 let clickable = props["action"].isTruthy && !context.isStreaming Group { if props.string("layout") == "carousel" { @@ -718,7 +718,7 @@ struct ImageTextView: View { @Environment(\.openUITheme) private var theme var body: some View { - let size = CGFloat(props.number("imageSize") ?? 40) + let size = CGFloat(min(max(props.number("imageSize").flatMap(\.finite) ?? 40, 0), 400)) let vertical = props.string("layout") == "vertical" let layout = vertical diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift index 9af572ba9c..053733f580 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ChartComponents.swift @@ -258,7 +258,8 @@ private struct ChartFrame: View { } var body: some View { - let height = max(props.number("height").map { CGFloat($0) } ?? theme.chartHeight, minHeight) + let height = max( + props.number("height").flatMap(\.finite).map { CGFloat($0) } ?? theme.chartHeight, minHeight) if isEmpty && (context.isStreaming || context.isQueryLoading) { SkeletonBlock(height: height, cornerRadius: 8) } else { @@ -779,7 +780,10 @@ struct ScatterChartView: View { var dots: [Dot] = [] for dataset in props.children("datasets") { for point in dataset.children("points") { - guard let x = point.number("x"), let y = point.number("y") else { continue } + // Like the other charts, a point that isn't a finite number is skipped. + guard let x = point.number("x").flatMap(\.finite), + let y = point.number("y").flatMap(\.finite) + else { continue } dots.append( Dot(id: dots.count, series: dataset.text("name"), x: x, y: y, z: point.number("z"))) } @@ -830,8 +834,13 @@ struct RadarChartView: View { var body: some View { let labels = props.array("labels").map(displayText) + // A value that isn't a finite number draws at the center, so it can't + // become the maximum that scales every other value to nothing. let all = props.children("series").map { series in - (name: series.text("category"), values: series.array("values").map { $0.numberValue ?? 0 }) + ( + name: series.text("category"), + values: series.array("values").map { $0.numberValue.flatMap(\.finite) ?? 0 } + ) } let colors = SeriesColors(all.map(\.name), theme.chartRamp(theme.radarChartPalette)) let series = all.filter { !hidden.contains($0.name) } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift index c3d0e4b60a..89417c819e 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift @@ -124,7 +124,8 @@ struct TextAreaView: View { var body: some View { let state = FieldContext(props, context: context, form: form) - let rows = max(Int(props.number("rows") ?? 3), 1) + // At most a screenful: the count comes from the response. + let rows = Int(min(max(props.number("rows").flatMap(\.finite) ?? 3, 1), 20)) TextField( props.text("placeholder"), text: Binding( @@ -462,11 +463,14 @@ struct SliderView: View { var body: some View { let state = FieldContext(props, context: context, form: form) - let minimum = props.number("min") ?? 0 - let maximum = max(props.number("max") ?? 100, minimum) + // The bounds come from the response; one that isn't a finite number + // (1e999, 0/0) falls back to react-ui's default rather than breaking the range. + let minimum = props.number("min").flatMap(\.finite) ?? 0 + let maximum = max(props.number("max").flatMap(\.finite) ?? 100, minimum) let discrete = props.string("variant") == "discrete" // react-ui steps a continuous slider by at least 1. - let step = discrete ? max(props.number("step") ?? 1, 0.0001) : max(1, props.number("step") ?? 1) + let step = + props.number("step").flatMap(\.finite).map { discrete ? max($0, 0.0001) : max($0, 1) } ?? 1 let stored = state.field.value.isNullish ? props["defaultValue"] : state.field.value let values = (stored.arrayValue ?? []).compactMap(\.numberValue) let current = values.isEmpty ? [minimum] : Array(values.prefix(2)) @@ -494,15 +498,24 @@ struct SliderView: View { } if current.count > 1 { RangeSlider( - lower: min(current[0], current[1]), upper: max(current[0], current[1]), + lower: RangeSlider.clamp(min(current[0], current[1]), to: minimum...maximum), + upper: RangeSlider.clamp(max(current[0], current[1]), to: minimum...maximum), bounds: minimum...maximum, step: step ) { set([$0, $1]) } - } else { + } else if (maximum - minimum) / step <= 100 { Slider( value: Binding( - get: { min(max(current[0], minimum), maximum) }, + get: { RangeSlider.clamp(current[0], to: minimum...maximum) }, set: { set([$0]) }), in: minimum...maximum, step: step) + } else { + // On the Mac a stepped Slider draws a tick mark per step, and AppKit + // never finishes laying out millions of them; the value snaps here. + Slider( + value: Binding( + get: { RangeSlider.clamp(current[0], to: minimum...maximum) }, + set: { set([RangeSlider.snap($0, bounds: minimum...maximum, step: step)]) }), + in: minimum...maximum) } HStack { Text(compactNumber(minimum)) @@ -532,7 +545,7 @@ struct SliderView: View { /// The values beside a slider's label: number fields, or menus of the steps /// when the slider is discrete. -private struct SliderValueControls: View { +struct SliderValueControls: View { let values: [Double] let minimum: Double let maximum: Double @@ -546,13 +559,13 @@ private struct SliderValueControls: View { private static let maximumMenuOptions = 200 var body: some View { - let options = discrete ? Self.options(minimum, maximum, step) : [] - let useMenus = discrete && options.count <= Self.maximumMenuOptions + let options = + discrete ? Self.options(minimum, maximum, step, limit: Self.maximumMenuOptions) : nil HStack(spacing: 6) { if values.count > 1 { let lower = values[0] let upper = values[1] - if useMenus { + if let options { menu(lower, options.filter { $0 < upper }) { onChange([$0, upper].sorted()) } separator menu(upper, options.filter { $0 > lower }) { onChange([lower, $0].sorted()) } @@ -563,7 +576,7 @@ private struct SliderValueControls: View { onChange([lower, $0]) } } - } else if useMenus { + } else if let options { menu(values[0], options) { onChange([$0]) } } else { SliderValueField(value: values[0], hasError: !(errors.first ?? "").isEmpty) { @@ -593,11 +606,13 @@ private struct SliderValueControls: View { .fixedSize() } - /// Every step from `minimum` to `maximum`, like react-ui's option list. - static func options(_ minimum: Double, _ maximum: Double, _ step: Double) -> [Double] { - let count = Int(((maximum - minimum) / step).rounded(.down)) + 1 - guard count > 0 else { return [] } - return (0.. [Double]? + { + let steps = ((maximum - minimum) / step).rounded(.down) + guard steps.isFinite, steps >= 0, steps < Double(limit) else { return steps < 0 ? [] : nil } + return (0...Int(steps)).map { minimum + Double($0) * step } } } @@ -716,11 +731,15 @@ struct RangeSlider: View { } } + static func clamp(_ value: Double, to bounds: ClosedRange) -> Double { + min(max(value, bounds.lowerBound), bounds.upperBound) + } + /// The nearest step to `value`, within `bounds`. static func snap(_ value: Double, bounds: ClosedRange, step: Double) -> Double { - guard step > 0 else { return min(max(value, bounds.lowerBound), bounds.upperBound) } + guard step > 0 else { return clamp(value, to: bounds) } let steps = ((value - bounds.lowerBound) / step).rounded() - return min(max(bounds.lowerBound + steps * step, bounds.lowerBound), bounds.upperBound) + return clamp(bounds.lowerBound + steps * step, to: bounds) } } diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift index aa56077cad..4812a73826 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/SelectionComponents.swift @@ -290,7 +290,7 @@ struct EditableTableView: View { _ position: Cell, rowId: String, column: OpenUIValue, value: OpenUIValue?, rowCount: Int ) -> some View { let index = position.column - let width = column["width"].numberValue.map { CGFloat($0) } ?? 120 + let width = column["width"].numberValue.flatMap(\.finite).map { CGFloat(max($0, 40)) } ?? 120 let original = displayText(value ?? .null) let binding = Binding( get: { edits[rowId, index] ?? original }, @@ -313,7 +313,6 @@ struct EditableTableView: View { .onSubmit { _ = move(1, from: position, rowCount: rowCount) } .onKeyPress(.upArrow) { move(-1, from: position, rowCount: rowCount) } .onKeyPress(.downArrow) { move(1, from: position, rowCount: rowCount) } - } } .frame(width: width) diff --git a/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift b/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift index ff99595149..b0d4939d18 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift +++ b/packages/swift-lang/Tests/OpenUILangTests/QueryAndFormTests.swift @@ -29,6 +29,22 @@ import Testing #expect(manager.result("unknown") == .null) } + /// A refresh interval comes straight from the response, so one too large + /// to schedule (or infinite) mustn't bring the app down. + @Test func survivesHugeRefreshIntervals() async { + let manager = QueryManager(toolProvider: FunctionToolProvider(["tick": { _ in 1 }])) + for interval in [Double.infinity, 1e30] { + manager.evaluateQueries([ + QueryNode( + statementId: "q", toolName: "tick", args: [:], defaults: 0, refreshInterval: interval, + deps: nil, complete: true) + ]) + await settle() + } + #expect(manager.result("q") == 1) + manager.dispose() + } + @Test func reportsMissingTools() async { let manager = QueryManager(toolProvider: FunctionToolProvider(["other": { _ in .null }])) manager.evaluateQueries([ diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index f0167c2b05..93b8c6abbc 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -192,6 +192,32 @@ import Testing #expect(errors.allSatisfy { $0.jsonRepresentation["source"] == "parser" }, "\(errors)") } + /// Numbers a response can hold but a layout can't use (1e999, 0/0, a + /// billion slider steps) render without crashing or hanging. + @Test(arguments: [ + #"TextArea("n", "p", 1e999)"#, + #"Slider("s", "discrete", 0, 1e999, 1)"#, + #"Slider("s", "discrete", 0, 1000000, 0.001)"#, + #"Slider("s", "continuous", 0/0, 10, 1)"#, + #"Slider("s", "continuous", 0, 100, 1, [10, 1e999])"#, + #"BarChart(["A"], [Series("S", [1])], "grouped", "x", "y", 1e999)"#, + #"RadarChart(["A", "B", "C"], [Series("S", [1, 1e999, 3])])"#, + #"ScatterChart([ScatterSeries("S", [Point(1, 2), Point(0/0, 1)])])"#, + ]) + func rendersNumbersALayoutCantUse(_ component: String) { + let host = NSHostingView( + rootView: OpenUIRenderer( + response: "root = Card([a])\na = \(component)", library: OpenUIChatLibrary.library + ) + .frame(width: 420)) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 420, height: 600), styleMask: [.borderless], + backing: .buffered, defer: false) + window.contentView = host + RunLoop.main.run(until: Date().addingTimeInterval(0.3)) + #expect(host.fittingSize.height > 20, "\(component) rendered \(host.fittingSize)") + } + /// Offered exactly its ideal height (a fixed frame, a self-sizing cell), /// a response lays out at that height. A VStack split the height by /// flexibility instead, cutting wrapping text short next to a row with a @@ -590,6 +616,20 @@ let globalTestLibrary = SwiftUILibrary( SliderView.errors([90, 10], minimum: 0, maximum: 100) == ["Min must be less than max", ""]) #expect(SliderView.errors([.nan], minimum: 0, maximum: 100) == ["Invalid number"]) } + + /// A discrete slider lists its steps in menus only while there are few, + /// and a huge range doesn't build them all to find out. + @Test func listsStepsOnlyWhileFew() { + #expect(SliderValueControls.options(0, 10, 2.5, limit: 200) == [0, 2.5, 5, 7.5, 10]) + #expect(SliderValueControls.options(0, 199, 1, limit: 200)?.count == 200) + #expect(SliderValueControls.options(0, 200, 1, limit: 200) == nil) + #expect(SliderValueControls.options(0, 1_000_000, 0.001, limit: 200) == nil) + } + + @Test func clampsToBounds() { + #expect(RangeSlider.clamp(140, to: 0...100) == 100) + #expect(RangeSlider.clamp(-3, to: 0...100) == 0) + } } /// The highlighter's token kinds, standing in for Prism's. From 5a65f61137ed5dfbea42deab95050c690deb50bd Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:46:41 +0530 Subject: [PATCH 43/52] fix(swift-lang): move range slider thumbs with the drag A drag's translation is measured from where it began, but each update added it to where the thumb had already moved to, so the thumb ran ahead of the finger and hit the other end of the range. The drag now starts from the thumb's position when it began. --- .../Components/FormComponents.swift | 18 +++++++++++++++--- .../OpenUISwiftUITests/RendererTests.swift | 5 +++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift index 89417c819e..f3d89f390f 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift @@ -661,6 +661,10 @@ struct RangeSlider: View { let step: Double let onChange: @MainActor (Double, Double) -> Void @Environment(\.isEnabled) private var isEnabled + /// Where each thumb (keyed by whether it's the lower one) was when its drag + /// began. A drag's translation is from there, not from where the thumb has + /// moved to since. + @State private var dragStarts: [Bool: CGFloat] = [:] private let thumbSize: CGFloat = 24 var body: some View { @@ -699,10 +703,13 @@ struct RangeSlider: View { .gesture( DragGesture(minimumDistance: 0) .onChanged { drag in - let span = bounds.upperBound - bounds.lowerBound - let position = offset(value, track) + drag.translation.width - move(isLower: isLower, to: bounds.lowerBound + Double(position / track) * span) + let start = dragStarts[isLower] ?? offset(value, track) + dragStarts[isLower] = start + move( + isLower: isLower, + to: Self.value(at: start + drag.translation.width, track: track, bounds: bounds)) } + .onEnded { _ in dragStarts[isLower] = nil } ) .accessibilityElement() .accessibilityLabel(isLower ? "Minimum" : "Maximum") @@ -731,6 +738,11 @@ struct RangeSlider: View { } } + /// The value at `offset` points along a `track` that spans `bounds`. + static func value(at offset: CGFloat, track: CGFloat, bounds: ClosedRange) -> Double { + bounds.lowerBound + Double(offset / track) * (bounds.upperBound - bounds.lowerBound) + } + static func clamp(_ value: Double, to bounds: ClosedRange) -> Double { min(max(value, bounds.lowerBound), bounds.upperBound) } diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 93b8c6abbc..29efeb4aa4 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -630,6 +630,11 @@ let globalTestLibrary = SwiftUILibrary( #expect(RangeSlider.clamp(140, to: 0...100) == 100) #expect(RangeSlider.clamp(-3, to: 0...100) == 0) } + + @Test func mapsTrackOffsetsToValues() { + #expect(RangeSlider.value(at: 50, track: 200, bounds: 0...100) == 25) + #expect(RangeSlider.value(at: 200, track: 200, bounds: 10...20) == 20) + } } /// The highlighter's token kinds, standing in for Prism's. From fed393d9dcc567394bbbf5e63b1280f8d0efb787 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:49:31 +0530 Subject: [PATCH 44/52] fix(swift-lang): keep long tags inside their block A tag wider than its container was laid out at its full width and ran off the card. Wrapping rows now give a child wider than a row the row's width, and tags stay on one line, cut short with an ellipsis, as react-ui's `max-width: 100%` and `text-overflow: ellipsis` do. --- .../Components/ContentComponents.swift | 2 ++ .../Components/IconComponents.swift | 3 +- .../Sources/OpenUISwiftUI/Support.swift | 23 ++++++++------- .../OpenUISwiftUITests/RendererTests.swift | 29 +++++++++++++++++++ 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift index 72717e3d74..3275ccbf0d 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/ContentComponents.swift @@ -737,7 +737,9 @@ struct TagBlockView: View { FlowLayout(spacing: theme.compactSpacing) { ForEach(Array(props.array("tags").enumerated()), id: \.offset) { _, tag in let size = props.string("size") + // Tags, like react-ui's: one line, cut short when wider than the block. Text(displayText(tag)) + .lineLimit(1) .font(font) .padding(tagPadding(size)) .background(theme.sunkSurface, in: RoundedRectangle(cornerRadius: tagRadius(size))) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift index 166dd24082..de31552c2c 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/IconComponents.swift @@ -408,7 +408,8 @@ struct TagLabel: View { let color = neutral ? Color.secondary : theme.status(variant) HStack(spacing: 4) { if let symbol { Image(systemName: symbol) } - Text(text) + // One line, cut short when the tag would be wider than its container. + Text(text).lineLimit(1) } .font(font) .foregroundStyle(onImage ? Color.white : neutral ? Color.primary : color) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift index beff6803cb..2014d712a3 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift @@ -339,7 +339,8 @@ struct MarkdownBlocks: View { } } -/// Lays children out in rows, wrapping to the next row when one is full. +/// Lays children out in rows, wrapping to the next row when one is full. A +/// child wider than a row gets the row's width, like CSS's `max-width: 100%`. struct FlowLayout: Layout { var spacing: CGFloat = 8 /// `.center` centers each row, like react-ui's centered legends. @@ -358,8 +359,7 @@ struct FlowLayout: Layout { var y = bounds.minY for row in arrange(subviews, width: bounds.width) { var x = alignment == .center ? bounds.minX + (bounds.width - row.width) / 2 : bounds.minX - for index in row.indices { - let size = subviews[index].sizeThatFits(.unspecified) + for (index, size) in row.items { subviews[index].place(at: CGPoint(x: x, y: y), proposal: ProposedViewSize(size)) x += size.width + spacing } @@ -368,7 +368,7 @@ struct FlowLayout: Layout { } private struct Row { - var indices: [Int] = [] + var items: [(index: Int, size: CGSize)] = [] var width: CGFloat = 0 var height: CGFloat = 0 } @@ -377,17 +377,20 @@ struct FlowLayout: Layout { var rows: [Row] = [] var current = Row() for index in subviews.indices { - let size = subviews[index].sizeThatFits(.unspecified) - let needed = current.indices.isEmpty ? size.width : current.width + spacing + size.width - if needed > width, !current.indices.isEmpty { + var size = subviews[index].sizeThatFits(.unspecified) + if size.width > width { + size = subviews[index].sizeThatFits(ProposedViewSize(width: width, height: nil)) + } + let needed = current.items.isEmpty ? size.width : current.width + spacing + size.width + if needed > width, !current.items.isEmpty { rows.append(current) current = Row() } - current.width = current.indices.isEmpty ? size.width : current.width + spacing + size.width + current.width = current.items.isEmpty ? size.width : current.width + spacing + size.width current.height = max(current.height, size.height) - current.indices.append(index) + current.items.append((index, size)) } - if !current.indices.isEmpty { rows.append(current) } + if !current.items.isEmpty { rows.append(current) } return rows } } diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 29efeb4aa4..9a64fa6b77 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -855,6 +855,35 @@ let globalTestLibrary = SwiftUILibrary( } } +/// Wrapping rows (tags, chips, legends) never let a child spill past the +/// container: one wider than a row gets the row's width. +@MainActor +@Suite struct FlowLayoutTests { + @Test func capsWideChildrenAtTheRowWidth() { + final class Box { var width: CGFloat = 0 } + let box = Box() + let host = NSHostingView( + rootView: FlowLayout { + Text("Short") + Text(String(repeating: "wide ", count: 60)) + .lineLimit(1) + .onGeometryChange(for: CGFloat.self) { + $0.size.width + } action: { + box.width = $0 + } + } + .frame(width: 200)) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 200, height: 200), styleMask: [.borderless], + backing: .buffered, defer: false) + window.contentView = host + RunLoop.main.run(until: Date().addingTimeInterval(0.2)) + #expect(box.width > 150) + #expect(box.width <= 200) + } +} + /// The flex layout behind openuiLibrary's Stack and Card, against what CSS /// flexbox does with react-ui's styles. @Suite struct FlexLayoutTests { From 269094d3d87f9e7737c9ba56e88db8abe5bd30c8 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:49:36 +0530 Subject: [PATCH 45/52] refactor(swift-lang): read markdown heading levels in a helper --- .../swift-lang/Sources/OpenUISwiftUI/Support.swift | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift index 2014d712a3..654aab2c45 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Support.swift @@ -290,12 +290,9 @@ struct MarkdownBlocks: View { } if line.isEmpty { flushParagraph() - } else if let hashes = line.prefix(while: { $0 == "#" }).count as Int?, hashes > 0, - hashes <= 6, - line.dropFirst(hashes).first == " " - { + } else if let level = headingLevel(line) { flushParagraph() - blocks.append(.heading(level: hashes, text: String(line.dropFirst(hashes + 1)))) + blocks.append(.heading(level: level, text: String(line.dropFirst(level + 1)))) } else if line == "---" || line == "***" { flushParagraph() blocks.append(.rule) @@ -325,6 +322,12 @@ struct MarkdownBlocks: View { return blocks } + /// The level of a `#`–`######` heading line. + private static func headingLevel(_ line: String) -> Int? { + let hashes = line.prefix { $0 == "#" }.count + return (1...6).contains(hashes) && line.dropFirst(hashes).first == " " ? hashes : nil + } + /// A fenced block's text, trimmed like react-ui's (`String(children).trim()`). private static func codeBlockText(_ lines: [String]) -> String { lines.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines) From c59e47c9236b4acda5a1181b084658d653bb8759 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:55:32 +0530 Subject: [PATCH 46/52] refactor(swift-lang): drop code nothing reads Library validation built codes and paths for its issues that only ever became one message, the generated openuiLibrary schemas aliased a rules object none of them use, and two views kept a value they never read. --- .../Scripts/generate-chat-components.mjs | 6 +- .../Sources/OpenUILang/CloudConfig.swift | 95 +++++-------------- .../Sources/OpenUILang/OpenUIComponents.swift | 3 - .../Components/CardComponents.swift | 1 - .../Components/FormComponents.swift | 2 - 5 files changed, 27 insertions(+), 80 deletions(-) diff --git a/packages/swift-lang/Scripts/generate-chat-components.mjs b/packages/swift-lang/Scripts/generate-chat-components.mjs index e255b3122f..5b551ca5b0 100644 --- a/packages/swift-lang/Scripts/generate-chat-components.mjs +++ b/packages/swift-lang/Scripts/generate-chat-components.mjs @@ -151,11 +151,15 @@ function generate({ lib, promptOptions, enumName, docs, shared }) { const all = names.map( (name) => ` ${reused(name) ? `${shared.enumName}.` : ""}${lowerFirst(name)},`, ); + // A library reusing another's schemas aliases its rules object only when one + // of its own schemas has form rules. const formRules = shared - ? ` /// The form \`rules\` object, for schemas that aren't shared. + ? schemas.some((schema) => /\bformRules\b/.test(schema)) + ? ` /// The form \`rules\` object, for schemas that aren't shared. static let formRules = ${shared.enumName}.formRules ` + : "" : ` /// The structured \`rules\` object shared by form fields. public static let formRules: PropType = .object( ["required", "email", "url", "numeric"].map { Prop($0, .boolean, .optional) } diff --git a/packages/swift-lang/Sources/OpenUILang/CloudConfig.swift b/packages/swift-lang/Sources/OpenUILang/CloudConfig.swift index 31ef78ec32..e553fe3e89 100644 --- a/packages/swift-lang/Sources/OpenUILang/CloudConfig.swift +++ b/packages/swift-lang/Sources/OpenUILang/CloudConfig.swift @@ -32,7 +32,7 @@ public func generateCloudConfig( if !issues.isEmpty { throw CloudConfigError( description: - "[generateSystemPrompt] Invalid library: \(issues.map(\.message).joined(separator: " "))") + "[generateSystemPrompt] Invalid library: \(issues.joined(separator: " "))") } var chatLibrary = library.objectValue ?? OpenUIObject() chatLibrary["components"] = nil @@ -78,80 +78,47 @@ private func cloudPromptOptions(_ options: PromptOptions) -> OpenUIObject? { // MARK: - Library validation -struct ChatLibraryIssue: Equatable { - enum Code: String { - case invalidShape = "invalid-shape" - case rootNotFound = "root-not-found" - case unresolvedRef = "unresolved-ref" - case unknownGroupComponent = "unknown-group-component" - case invalidRequired = "invalid-required" - } - - var code: Code - var message: String - /// e.g. "$defs/Card/properties/children/items" - var path: String? -} - -/// Structural checks Cloud applies to a library, reporting every issue in one pass. -func validateChatLibrary(_ library: OpenUIValue) -> [ChatLibraryIssue] { +/// Structural checks Cloud applies to a library, reporting every issue in one +/// pass. lang-core's issues also carry a code and a path, but only their +/// messages are ever read, so these are the messages. +func validateChatLibrary(_ library: OpenUIValue) -> [String] { guard let spec = library.objectValue else { - return [ChatLibraryIssue(code: .invalidShape, message: "chatLibrary must be an object.")] + return ["chatLibrary must be an object."] } - var issues: [ChatLibraryIssue] = [] + var issues: [String] = [] let root = spec["root"] ?? .undefined let rootName = root.stringValue.flatMap { $0.isEmpty ? nil : $0 } if root != .undefined, rootName == nil { - issues.append( - ChatLibraryIssue( - code: .invalidShape, - message: "chatLibrary.root, when present, must be a non-empty string.", path: "root")) + issues.append("chatLibrary.root, when present, must be a non-empty string.") } guard let schema = spec["schema"]?.objectValue else { - issues.append( - ChatLibraryIssue( - code: .invalidShape, - message: "chatLibrary.schema must be an object with a $defs map of component schemas.", - path: "schema")) + issues.append("chatLibrary.schema must be an object with a $defs map of component schemas.") return issues } guard let defs = schema["$defs"]?.objectValue, !defs.isEmpty else { - issues.append( - ChatLibraryIssue( - code: .invalidShape, - message: "chatLibrary.schema.$defs must be a non-empty object keyed by component name.", - path: "schema/$defs")) + issues.append("chatLibrary.schema.$defs must be a non-empty object keyed by component name.") return issues } let defNames = Set(defs.keys) if let rootName, !defNames.contains(rootName) { issues.append( - ChatLibraryIssue( - code: .rootNotFound, - message: - "Root component \"\(rootName)\" was not found in schema.$defs. Available components: \(defs.keys.joined(separator: ", ")).", - path: "root")) + "Root component \"\(rootName)\" was not found in schema.$defs. Available components: \(defs.keys.joined(separator: ", "))." + ) } for (name, def) in defs.entries { let defPath = "$defs/\(name)" guard let component = def.objectValue else { - issues.append( - ChatLibraryIssue( - code: .invalidShape, message: "\(defPath) must be an object component schema.", - path: defPath)) + issues.append("\(defPath) must be an object component schema.") continue } let properties = component["properties"] ?? .undefined if properties != .undefined, properties.objectValue == nil { - issues.append( - ChatLibraryIssue( - code: .invalidShape, message: "\(defPath)/properties must be an object.", - path: "\(defPath)/properties")) + issues.append("\(defPath)/properties must be an object.") } let required = component["required"] ?? .undefined @@ -160,18 +127,10 @@ func validateChatLibrary(_ library: OpenUIValue) -> [ChatLibraryIssue] { if let names, names.allSatisfy({ $0 != nil }) { let propKeys = Set(properties.objectValue?.keys ?? []) for case let name? in names where !propKeys.contains(name) { - issues.append( - ChatLibraryIssue( - code: .invalidRequired, - message: "\(defPath) lists required property \"\(name)\" that is not in properties.", - path: "\(defPath)/required")) + issues.append("\(defPath) lists required property \"\(name)\" that is not in properties.") } } else { - issues.append( - ChatLibraryIssue( - code: .invalidRequired, - message: "\(defPath)/required must be an array of property names.", - path: "\(defPath)/required")) + issues.append("\(defPath)/required must be an array of property names.") } } @@ -182,21 +141,14 @@ func validateChatLibrary(_ library: OpenUIValue) -> [ChatLibraryIssue] { guard let groupName = group["name"].stringValue, let components = group["components"].arrayValue else { issues.append( - ChatLibraryIssue( - code: .invalidShape, - message: - "Each componentGroups entry must be {name: string, components: string[], notes?: string[]}.", - path: "componentGroups")) + "Each componentGroups entry must be {name: string, components: string[], notes?: string[]}." + ) continue } for component in components where !(component.stringValue.map { defNames.contains($0) } ?? false) { issues.append( - ChatLibraryIssue( - code: .unknownGroupComponent, - message: - "Component group \"\(groupName)\" references unknown component \"\(component.jsString)\".", - path: "componentGroups")) + "Component group \"\(groupName)\" references unknown component \"\(component.jsString)\".") } } @@ -205,7 +157,7 @@ func validateChatLibrary(_ library: OpenUIValue) -> [ChatLibraryIssue] { /// Checks every `$ref` below `node` resolves to a component in `$defs`. private func collectRefIssues( - _ node: OpenUIValue, _ path: String, _ defNames: Set, _ issues: inout [ChatLibraryIssue] + _ node: OpenUIValue, _ path: String, _ defNames: Set, _ issues: inout [String] ) { if let items = node.arrayValue { for (i, item) in items.enumerated() { @@ -217,11 +169,8 @@ private func collectRefIssues( if let ref = object["$ref"]?.stringValue, !refResolves(ref, defNames) { issues.append( - ChatLibraryIssue( - code: .unresolvedRef, - message: - "Unresolvable $ref \"\(ref)\" at \(path) — refs must be \"#/$defs/\" pointing at a component in $defs.", - path: path)) + "Unresolvable $ref \"\(ref)\" at \(path) — refs must be \"#/$defs/\" pointing at a component in $defs." + ) } for (key, value) in object.entries where key != "$ref" { collectRefIssues(value, "\(path)/\(key)", defNames, &issues) diff --git a/packages/swift-lang/Sources/OpenUILang/OpenUIComponents.swift b/packages/swift-lang/Sources/OpenUILang/OpenUIComponents.swift index ffbd55441c..3421b2afa3 100644 --- a/packages/swift-lang/Sources/OpenUILang/OpenUIComponents.swift +++ b/packages/swift-lang/Sources/OpenUILang/OpenUIComponents.swift @@ -8,9 +8,6 @@ /// Components both libraries define the same way are `ChatComponents`' /// schemas. public enum OpenUIComponents { - /// The form `rules` object, for schemas that aren't shared. - static let formRules = ChatComponents.formRules - public static let card = ComponentSchema( "Card", description: diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift index fc5a9238be..00499252c3 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift @@ -715,7 +715,6 @@ private struct TitleStack: View { struct ImageTextView: View { let props: ComponentProps - @Environment(\.openUITheme) private var theme var body: some View { let size = CGFloat(min(max(props.number("imageSize").flatMap(\.finite) ?? 40, 0), 400)) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift index f3d89f390f..de3eb6a42e 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift @@ -52,13 +52,11 @@ struct LabelView: View { private struct FieldContext { let field: StateField let rules: [ParsedRule] - let form: String? @MainActor init(_ props: ComponentProps, context: OpenUIContext, form: String?) { self.field = context.stateField(name: props.text("name"), binding: props["value"], form: form) self.rules = parseStructuredRules(props["rules"]) - self.form = form } } From 20a9fb0f01b454f6bd0a8c9bd28e2396646b1a3d Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:55:32 +0530 Subject: [PATCH 47/52] fix(swift-lang): keep a date range's ends from crossing Each end of a range DatePicker could be set past the other, storing a `to` before its `from`. Each end is now bounded by the other, as react-ui's range calendar does. --- .../Components/FormComponents.swift | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift index de3eb6a42e..57cf9c1e63 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift @@ -427,17 +427,24 @@ struct DatePickerView: View { private func rangePicker(_ label: String, key: String, _ state: FieldContext) -> some View { let range = state.field.value.objectValue ?? OpenUIObject() - return DatePicker( - label, - selection: Binding( - get: { range[key]?.stringValue.flatMap(dayFormatter.date(from:)) ?? Date() }, - set: { date in - var next = range - next[key] = .string(dayFormatter.string(from: date)) - set(state, .object(next)) - }), - displayedComponents: .date - ) + let day = { (key: String) in range[key]?.stringValue.flatMap(dayFormatter.date(from:)) } + let selection = Binding( + get: { day(key) ?? Date() }, + set: { (date: Date) in + var next = range + next[key] = .string(dayFormatter.string(from: date)) + set(state, .object(next)) + }) + // The ends can't cross, as in react-ui's range calendar. + return Group { + if key == "from", let to = day("to") { + DatePicker(label, selection: selection, in: ...to, displayedComponents: .date) + } else if key == "to", let from = day("from") { + DatePicker(label, selection: selection, in: from..., displayedComponents: .date) + } else { + DatePicker(label, selection: selection, displayedComponents: .date) + } + } .disabled(context.isStreaming) } From 5b4273d91db3d069dfab9534665f17550d388c3b Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Thu, 8 Oct 2026 08:32:17 +0530 Subject: [PATCH 48/52] fix(swift-lang): skip a visual card's text panel when it has no text A response can bind a card's text to values that come out empty, most often by using an @Each loop variable in a separate statement, which can't see it. The card then drew an empty white panel over its photo. It now shows just the photo; the README lists this with the other differences from react-ui, which draws the empty panel. --- packages/swift-lang/README.md | 1 + .../Components/CardComponents.swift | 12 ++++++++++- .../OpenUISwiftUITests/RendererTests.swift | 20 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/swift-lang/README.md b/packages/swift-lang/README.md index 7c73bd6cbc..db0d1421c8 100644 --- a/packages/swift-lang/README.md +++ b/packages/swift-lang/README.md @@ -247,6 +247,7 @@ Conform your own type to `ToolProvider` for other backends. - Touch has no hover, so a chart's tooltip opens on a tap and stays until the same spot is tapped again (or another chart's opens), where react-ui shows it while a finger moves. Hover states need a pointer: the Mac, or an iPad with a trackpad. - Editable table cells are always text fields, which suits touch, rather than react-ui's select-then-edit cells. With a keyboard, Up and Down move between rows and Enter moves down; Escape doesn't undo an edit. - Crowded chart axes keep thinning their labels until the longest fits, down to three labels. react-ui stops thinning once each label has 40px and truncates the rest. +- A visual card whose text block came out empty (say, a loop variable used outside its `@Each`) shows just its photo, where react-ui draws an empty panel over it. - The image gallery's mosaic has fixed proportions instead of taking its height from the loaded images, so it doesn't jump when they arrive, and the viewer shows each image's `details`. - Not ported: `jsonToOpenUI`, the deprecated `enrichErrors` (its hints are in `onError`), and the server-side `artifactTool` from `@openuidev/lang-core/cloud`. diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift index 00499252c3..4778ca0c2d 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/CardComponents.swift @@ -571,7 +571,7 @@ private struct VisualCard: View { .frame(minHeight: 24, alignment: .top) .padding(12) Spacer(minLength: 0) - if !item["body"].isNullish { + if textBlockHasContent(item["body"]) { OpenUINode(item["body"]) .padding(.vertical, 8) .padding(.horizontal, 10) @@ -598,6 +598,16 @@ private struct VisualCard: View { // MARK: - Building blocks +/// Whether a card's text block (`Text`, `BoldText`) has anything to show. A +/// response can bind one to values that come out empty (a loop variable used +/// outside its `@Each`), and its panel would then float empty over the photo. +func textBlockHasContent(_ value: OpenUIValue) -> Bool { + guard let element = value.elementValue, ["Text", "BoldText"].contains(element.typeName) else { + return !value.isNullish + } + return ["value", "subtext"].contains { !displayText(element.props[$0] ?? .undefined).isEmpty } +} + /// `Text` / `BoldText`: a value line with optional subtext. `variant "number"` /// uses tabular digits; `subtextVariant "metric"` colors a leading +/- green/red. struct TextLineView: View { diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 9a64fa6b77..5d096700c3 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -22,6 +22,26 @@ import Testing } } +/// A card's text block counts as content only when it has text: one whose +/// values came out empty doesn't get an empty panel over the photo. +@Suite struct CardTextContentTests { + func block(_ type: String, _ props: OpenUIObject) -> OpenUIValue { + .element(ElementNode(typeName: type, props: props, partial: false)) + } + + @Test func emptyTextBlocksHaveNoContent() { + #expect(!textBlockHasContent(block("BoldText", ["value": "", "subtext": ""]))) + #expect(!textBlockHasContent(block("Text", ["value": .null]))) + #expect(!textBlockHasContent(.null)) + } + + @Test func textOrOtherComponentsAreContent() { + #expect(textBlockHasContent(block("BoldText", ["value": "", "subtext": "Temple"]))) + #expect(textBlockHasContent(block("Text", ["value": 0]))) + #expect(textBlockHasContent(block("TagBlock", ["tags": []]))) + } +} + @Suite struct CardActionTests { let item: OpenUIObject = ["itemIndex": 1, "itemId": "a", "itemTitle": .undefined] From 8779745df1bb3fc741763839beb8bb1e2c532efe Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Thu, 8 Oct 2026 13:26:06 +0530 Subject: [PATCH 49/52] test(swift-lang): write fixtures one case per line Pretty-printed, the fixtures generated from the TypeScript packages took about 39k lines, most of this package's diff, for data nobody reads value by value. They're now one case per line: still JSON with the same contents, still diffable case by case, and the CI job that regenerates them still compares byte for byte. --- .../swift-lang/Scripts/generate-fixtures.mjs | 55 +- .../OpenUILangTests/Fixtures/chat-spec.json | 539 +- .../Tests/OpenUILangTests/Fixtures/cloud.json | 379 +- .../OpenUILangTests/Fixtures/errors.json | 124 +- .../OpenUILangTests/Fixtures/evaluation.json | 4763 +------ .../Tests/OpenUILangTests/Fixtures/merge.json | 134 +- .../OpenUILangTests/Fixtures/messages.json | 376 +- .../OpenUILangTests/Fixtures/openui-spec.json | 4754 +------ .../OpenUILangTests/Fixtures/parser.json | 7205 +--------- .../OpenUILangTests/Fixtures/prompts.json | 11180 +--------------- .../OpenUILangTests/Fixtures/schemas.json | 8681 +----------- .../OpenUILangTests/Fixtures/stream-set.json | 673 +- .../OpenUILangTests/Fixtures/streaming.json | 67 +- .../Fixtures/chart-formats.json | 174 +- .../Fixtures/chat-examples.json | 25 +- .../Fixtures/openui-examples.json | 30 +- 16 files changed, 286 insertions(+), 38873 deletions(-) diff --git a/packages/swift-lang/Scripts/generate-fixtures.mjs b/packages/swift-lang/Scripts/generate-fixtures.mjs index b1e251d43d..287ea8b546 100644 --- a/packages/swift-lang/Scripts/generate-fixtures.mjs +++ b/packages/swift-lang/Scripts/generate-fixtures.mjs @@ -766,14 +766,29 @@ const chartFormatCases = [ })); Number.prototype.toLocaleString = toLocaleString; -function write(name, data, indent = 1) { - mkdirSync(fixtures, { recursive: true }); - writeFileSync(join(fixtures, name), JSON.stringify(data, null, indent) + "\n"); +// One case per line: still JSON and still diffable case by case, without a +// line for every value. Pretty-printed, the fixtures were most of the +// package's lines. +function fixtureJSON(data) { + const array = Array.isArray(data); + const lines = array + ? data.map((item) => JSON.stringify(item)) + : Object.entries(data).map( + ([key, value]) => `${JSON.stringify(key)}: ${JSON.stringify(value)}`, + ); + return `${array ? "[" : "{"}\n${lines.join(",\n")}\n${array ? "]" : "}"}\n`; +} + +const swiftUIFixtures = join(here, "..", "Tests", "OpenUISwiftUITests", "Fixtures"); + +function write(name, data, folder = fixtures) { + mkdirSync(folder, { recursive: true }); + writeFileSync(join(folder, name), fixtureJSON(data)); } write("schemas.json", Object.fromEntries(Object.entries(schemas))); write("parser.json", parserCases); -write("streaming.json", streamingCases, 0); +write("streaming.json", streamingCases); write("stream-set.json", setCases); write("evaluation.json", evalFixtures); write("prompts.json", promptCases); @@ -781,31 +796,21 @@ write("merge.json", mergeCases); write("errors.json", errorCases); write("cloud.json", { cases: cloudCases, chat: chatCloud }); write("messages.json", messageCases); - -// The chat examples, for the SwiftUI renderer's end-to-end render tests. -mkdirSync(join(here, "..", "Tests", "OpenUISwiftUITests", "Fixtures"), { recursive: true }); -writeFileSync( - join(here, "..", "Tests", "OpenUISwiftUITests", "Fixtures", "chat-examples.json"), - JSON.stringify( - chatExamples.map(({ name, input }) => ({ name, input })), - null, - 1, - ) + "\n", -); write("chat-spec.json", chatComponentSpecs); write("openui-spec.json", openuiSpec); -writeFileSync( - join(here, "..", "Tests", "OpenUISwiftUITests", "Fixtures", "openui-examples.json"), - JSON.stringify( - openuiExamples.map(({ name, input }) => ({ name, input })), - null, - 1, - ) + "\n", +// The libraries' examples, for the SwiftUI renderer's end-to-end render +// tests, and react-ui's chart number formats. +write( + "chat-examples.json", + chatExamples.map(({ name, input }) => ({ name, input })), + swiftUIFixtures, ); -writeFileSync( - join(here, "..", "Tests", "OpenUISwiftUITests", "Fixtures", "chart-formats.json"), - JSON.stringify(chartFormatCases, null, 1) + "\n", +write( + "openui-examples.json", + openuiExamples.map(({ name, input }) => ({ name, input })), + swiftUIFixtures, ); +write("chart-formats.json", chartFormatCases, swiftUIFixtures); console.log( `wrote ${parserCases.length} parser, ${streamingCases.length} streaming, ${setCases.length} set, ${evalFixtures.length} evaluation, ${promptCases.length} prompt, ${mergeCases.length} merge, ${errorCases.length} error, ${cloudCases.length} cloud, ${messageCases.separate.length} message, ${chartFormatCases.length} chart format fixtures`, diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/chat-spec.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/chat-spec.json index 4117eccb92..4a32f0c3a3 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/chat-spec.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/chat-spec.json @@ -1,538 +1,5 @@ { - "root": "Card", - "components": { - "Card": { - "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", - "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." - }, - "CardHeader": { - "signature": "CardHeader(title?: string, subtitle?: string)", - "description": "Header with optional title and subtitle" - }, - "TextContent": { - "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "MarkDownRenderer": { - "signature": "MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")", - "description": "Renders markdown text with optional container variant" - }, - "Callout": { - "signature": "Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)", - "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." - }, - "TextCallout": { - "signature": "TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)", - "description": "Text callout with variant, title, and description" - }, - "Image": { - "signature": "Image(alt: string, src?: string)", - "description": "Image with alt text and optional URL" - }, - "ImageBlock": { - "signature": "ImageBlock(src: string, alt?: string)", - "description": "Image block with loading state" - }, - "ImageGallery": { - "signature": "ImageGallery(images: {src: string, alt?: string, details?: string}[])", - "description": "Gallery grid of images with modal preview" - }, - "CodeBlock": { - "signature": "CodeBlock(language: string, codeString: string)", - "description": "Syntax-highlighted code block" - }, - "Separator": { - "signature": "Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)", - "description": "Visual divider between content sections" - }, - "Table": { - "signature": "Table(columns: Col[])", - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", - "description": "Column definition — holds label + data array" - }, - "BarChart": { - "signature": "BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Vertical bars; use for comparing values across categories with one or more series" - }, - "LineChart": { - "signature": "LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Lines over categories; use for trends and continuous data over time" - }, - "AreaChart": { - "signature": "AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Filled area under lines; use for cumulative totals or volume trends over time" - }, - "RadarChart": { - "signature": "RadarChart(labels: string[], series: Series[])", - "description": "Spider/web chart; use for comparing multiple variables across one or more entities" - }, - "HorizontalBarChart": { - "signature": "HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)", - "description": "Horizontal bars; prefer when category labels are long or for ranked lists" - }, - "Series": { - "signature": "Series(category: string, values: number[])", - "description": "One data series" - }, - "PieChart": { - "signature": "PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")", - "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" - }, - "RadialChart": { - "signature": "RadialChart(labels: string[], values: number[])", - "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" - }, - "SingleStackedBarChart": { - "signature": "SingleStackedBarChart(labels: string[], values: number[])", - "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" - }, - "Slice": { - "signature": "Slice(category: string, value: number)", - "description": "One slice with label and numeric value" - }, - "ScatterChart": { - "signature": "ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)", - "description": "X/Y scatter plot; use for correlations, distributions, and clustering" - }, - "ScatterSeries": { - "signature": "ScatterSeries(name: string, points: Point[])", - "description": "Named dataset" - }, - "Point": { - "signature": "Point(x: number, y: number, z?: number)", - "description": "Data point with numeric coordinates" - }, - "Form": { - "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", - "description": "Form container with fields and explicit action buttons" - }, - "FormControl": { - "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", - "description": "Field with label, input component, and optional hint text" - }, - "Label": { - "signature": "Label(text: string)", - "description": "Text label" - }, - "Input": { - "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "TextArea": { - "signature": "TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Select": { - "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", - "description": "" - }, - "SelectItem": { - "signature": "SelectItem(value: string, label: string)", - "description": "Option for Select" - }, - "DatePicker": { - "signature": "DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Slider": { - "signature": "Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "Numeric slider input; supports continuous and discrete (stepped) variants" - }, - "CheckBoxGroup": { - "signature": "CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)", - "description": "" - }, - "CheckBoxItem": { - "signature": "CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)", - "description": "" - }, - "RadioGroup": { - "signature": "RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "RadioItem": { - "signature": "RadioItem(label: string, description: string, value: string)", - "description": "" - }, - "SwitchGroup": { - "signature": "SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)", - "description": "Group of switch toggles" - }, - "SwitchItem": { - "signature": "SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)", - "description": "Individual switch toggle" - }, - "Button": { - "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", - "description": "Clickable button" - }, - "Buttons": { - "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "ListBlock": { - "signature": "ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")", - "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." - }, - "ListItem": { - "signature": "ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)", - "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." - }, - "FollowUpBlock": { - "signature": "FollowUpBlock(items: FollowUpItem[])", - "description": "List of clickable follow-up suggestions placed at the end of a response" - }, - "FollowUpItem": { - "signature": "FollowUpItem(text: string)", - "description": "Clickable follow-up suggestion — when clicked, sends text as user message" - }, - "SectionBlock": { - "signature": "SectionBlock(sections: SectionItem[], isFoldable?: boolean)", - "description": "Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section." - }, - "SectionItem": { - "signature": "SectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[])", - "description": "Section with a label and collapsible content — used inside SectionBlock" - }, - "Tabs": { - "signature": "Tabs(items: TabItem[])", - "description": "Tabbed container" - }, - "TabItem": { - "signature": "TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[])", - "description": "value is unique id, trigger is tab label, content is array of components" - }, - "Accordion": { - "signature": "Accordion(items: AccordionItem[])", - "description": "Collapsible sections" - }, - "AccordionItem": { - "signature": "AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[])", - "description": "value is unique id, trigger is section title" - }, - "Steps": { - "signature": "Steps(items: StepsItem[])", - "description": "Step-by-step guide" - }, - "StepsItem": { - "signature": "StepsItem(title: string, details: string)", - "description": "title and details text for one step" - }, - "Carousel": { - "signature": "Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\")", - "description": "Horizontal scrollable carousel" - }, - "TagBlock": { - "signature": "TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")", - "description": "tags is an array of strings; optional size sm | md | lg" - }, - "Tag": { - "signature": "Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")", - "description": "Styled tag/badge with optional Icon and variant" - }, - "EntityList": { - "signature": "EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})", - "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." - }, - "InlineHeader": { - "signature": "InlineHeader(heading: string, description?: string)", - "description": "Compact section heading with an optional one-line description, for use inside cards." - }, - "Icon": { - "signature": "Icon(name: string, category?: string)", - "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." - }, - "IconButton": { - "signature": "IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")", - "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." - }, - "EditableTable": { - "signature": "EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])", - "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" - }, - "ChipItem": { - "signature": "ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)", - "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." - }, - "Chips": { - "signature": "Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", - "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." - }, - "OptionCard": { - "signature": "OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)", - "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." - }, - "OptionCards": { - "signature": "OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", - "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." - }, - "Text": { - "signature": "Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", - "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "BoldText": { - "signature": "BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", - "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "IconText": { - "signature": "IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")", - "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." - }, - "ImageText": { - "signature": "ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)", - "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." - }, - "ImageTextLarge": { - "signature": "ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)", - "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." - }, - "MetricIndicatorInline": { - "signature": "MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})", - "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." - }, - "MetricIndicatorWithStrikethrough": { - "signature": "MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})", - "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." - }, - "SnippetCardItem": { - "signature": "SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)", - "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." - }, - "SnippetCardBlock": { - "signature": "SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." - }, - "OverviewCardItem": { - "signature": "OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)", - "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." - }, - "OverviewCardBlock": { - "signature": "OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." - }, - "ContextCardItem": { - "signature": "ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)", - "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." - }, - "ContextCardBlock": { - "signature": "ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." - }, - "CompositeCardItem": { - "signature": "CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})", - "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." - }, - "CompositeCardBlock": { - "signature": "CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." - }, - "VisualCardItem": { - "signature": "VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)", - "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." - }, - "VisualCardBlock": { - "signature": "VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." - } - }, - "componentGroups": [ - { - "name": "Content", - "components": [ - "CardHeader", - "TextContent", - "MarkDownRenderer", - "Callout", - "TextCallout", - "Image", - "ImageBlock", - "ImageGallery", - "CodeBlock", - "Separator", - "InlineHeader" - ], - "notes": [ - "- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).", - "- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card." - ] - }, - { - "name": "Tables", - "components": [ - "Table", - "Col", - "EditableTable" - ], - "notes": [ - "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", - "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes." - ] - }, - { - "name": "Charts (2D)", - "components": [ - "BarChart", - "LineChart", - "AreaChart", - "RadarChart", - "HorizontalBarChart", - "Series" - ] - }, - { - "name": "Charts (1D)", - "components": [ - "PieChart", - "RadialChart", - "SingleStackedBarChart", - "Slice" - ] - }, - { - "name": "Charts (Scatter)", - "components": [ - "ScatterChart", - "ScatterSeries", - "Point" - ] - }, - { - "name": "Forms", - "components": [ - "Form", - "FormControl", - "Label", - "Input", - "TextArea", - "Select", - "SelectItem", - "DatePicker", - "Slider", - "CheckBoxGroup", - "CheckBoxItem", - "RadioGroup", - "RadioItem", - "SwitchGroup", - "SwitchItem", - "Chips", - "ChipItem", - "OptionCards", - "OptionCard" - ], - "notes": [ - "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", - "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", - "- Define EACH FormControl as its own reference — do NOT inline all controls in one array.", - "- NEVER nest Form inside Form.", - "- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).", - "- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }", - "- The renderer shows error messages automatically — do NOT generate error text in the UI" - ] - }, - { - "name": "Buttons", - "components": [ - "Button", - "Buttons", - "Icon", - "IconButton" - ], - "notes": [ - "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard." - ] - }, - { - "name": "Lists & Follow-ups", - "components": [ - "ListBlock", - "ListItem", - "FollowUpBlock", - "FollowUpItem" - ], - "notes": [ - "- Use ListBlock with ListItem references for numbered lists.", - "- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.", - "- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.", - "- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.", - "- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })" - ] - }, - { - "name": "Sections", - "components": [ - "SectionBlock", - "SectionItem" - ], - "notes": [ - "- SectionBlock renders collapsible accordion sections that auto-open as they stream.", - "- Each section needs a unique `value` id, a `trigger` label, and a `content` array.", - "- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])", - "- Set isFoldable=false to render sections as flat headers instead of accordion." - ] - }, - { - "name": "Layout", - "components": [ - "Tabs", - "TabItem", - "Accordion", - "AccordionItem", - "Steps", - "StepsItem", - "Carousel" - ], - "notes": [ - "- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.", - "- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])", - "- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.", - "- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.", - "- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs." - ] - }, - { - "name": "Data Display", - "components": [ - "TagBlock", - "Tag", - "EntityList" - ], - "notes": [ - "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not." - ] - }, - { - "name": "Cards", - "components": [ - "SnippetCardBlock", - "SnippetCardItem", - "OverviewCardBlock", - "OverviewCardItem", - "ContextCardBlock", - "ContextCardItem", - "CompositeCardBlock", - "CompositeCardItem", - "VisualCardBlock", - "VisualCardItem", - "Text", - "BoldText", - "IconText", - "ImageText", - "ImageTextLarge", - "MetricIndicatorInline", - "MetricIndicatorWithStrikethrough" - ], - "notes": [ - "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", - "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", - "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", - "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", - "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", - "- VisualCardItem: image-first card with a BoldText body and optional Tag.", - "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card." - ] - } - ] +"root": "Card", +"components": {"Card":{"signature":"Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])","description":"Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent."},"CardHeader":{"signature":"CardHeader(title?: string, subtitle?: string)","description":"Header with optional title and subtitle"},"TextContent":{"signature":"TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")","description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"MarkDownRenderer":{"signature":"MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")","description":"Renders markdown text with optional container variant"},"Callout":{"signature":"Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)","description":"Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false."},"TextCallout":{"signature":"TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)","description":"Text callout with variant, title, and description"},"Image":{"signature":"Image(alt: string, src?: string)","description":"Image with alt text and optional URL"},"ImageBlock":{"signature":"ImageBlock(src: string, alt?: string)","description":"Image block with loading state"},"ImageGallery":{"signature":"ImageGallery(images: {src: string, alt?: string, details?: string}[])","description":"Gallery grid of images with modal preview"},"CodeBlock":{"signature":"CodeBlock(language: string, codeString: string)","description":"Syntax-highlighted code block"},"Separator":{"signature":"Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)","description":"Visual divider between content sections"},"Table":{"signature":"Table(columns: Col[])","description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"signature":"Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")","description":"Column definition — holds label + data array"},"BarChart":{"signature":"BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)","description":"Vertical bars; use for comparing values across categories with one or more series"},"LineChart":{"signature":"LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)","description":"Lines over categories; use for trends and continuous data over time"},"AreaChart":{"signature":"AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)","description":"Filled area under lines; use for cumulative totals or volume trends over time"},"RadarChart":{"signature":"RadarChart(labels: string[], series: Series[])","description":"Spider/web chart; use for comparing multiple variables across one or more entities"},"HorizontalBarChart":{"signature":"HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)","description":"Horizontal bars; prefer when category labels are long or for ranked lists"},"Series":{"signature":"Series(category: string, values: number[])","description":"One data series"},"PieChart":{"signature":"PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")","description":"Circular slices; use plucked arrays: PieChart(data.categories, data.values)"},"RadialChart":{"signature":"RadialChart(labels: string[], values: number[])","description":"Radial bars; use plucked arrays: RadialChart(data.categories, data.values)"},"SingleStackedBarChart":{"signature":"SingleStackedBarChart(labels: string[], values: number[])","description":"Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)"},"Slice":{"signature":"Slice(category: string, value: number)","description":"One slice with label and numeric value"},"ScatterChart":{"signature":"ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)","description":"X/Y scatter plot; use for correlations, distributions, and clustering"},"ScatterSeries":{"signature":"ScatterSeries(name: string, points: Point[])","description":"Named dataset"},"Point":{"signature":"Point(x: number, y: number, z?: number)","description":"Data point with numeric coordinates"},"Form":{"signature":"Form(name: string, buttons: Buttons, fields?: FormControl[])","description":"Form container with fields and explicit action buttons"},"FormControl":{"signature":"FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)","description":"Field with label, input component, and optional hint text"},"Label":{"signature":"Label(text: string)","description":"Text label"},"Input":{"signature":"Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"TextArea":{"signature":"TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Select":{"signature":"Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")","description":""},"SelectItem":{"signature":"SelectItem(value: string, label: string)","description":"Option for Select"},"DatePicker":{"signature":"DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Slider":{"signature":"Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":"Numeric slider input; supports continuous and discrete (stepped) variants"},"CheckBoxGroup":{"signature":"CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)","description":""},"CheckBoxItem":{"signature":"CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)","description":""},"RadioGroup":{"signature":"RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"RadioItem":{"signature":"RadioItem(label: string, description: string, value: string)","description":""},"SwitchGroup":{"signature":"SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)","description":"Group of switch toggles"},"SwitchItem":{"signature":"SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)","description":"Individual switch toggle"},"Button":{"signature":"Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")","description":"Clickable button"},"Buttons":{"signature":"Buttons(buttons: Button[], direction?: \"row\" | \"column\")","description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"ListBlock":{"signature":"ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")","description":"A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list."},"ListItem":{"signature":"ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)","description":"Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable."},"FollowUpBlock":{"signature":"FollowUpBlock(items: FollowUpItem[])","description":"List of clickable follow-up suggestions placed at the end of a response"},"FollowUpItem":{"signature":"FollowUpItem(text: string)","description":"Clickable follow-up suggestion — when clicked, sends text as user message"},"SectionBlock":{"signature":"SectionBlock(sections: SectionItem[], isFoldable?: boolean)","description":"Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section."},"SectionItem":{"signature":"SectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[])","description":"Section with a label and collapsible content — used inside SectionBlock"},"Tabs":{"signature":"Tabs(items: TabItem[])","description":"Tabbed container"},"TabItem":{"signature":"TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[])","description":"value is unique id, trigger is tab label, content is array of components"},"Accordion":{"signature":"Accordion(items: AccordionItem[])","description":"Collapsible sections"},"AccordionItem":{"signature":"AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[])","description":"value is unique id, trigger is section title"},"Steps":{"signature":"Steps(items: StepsItem[])","description":"Step-by-step guide"},"StepsItem":{"signature":"StepsItem(title: string, details: string)","description":"title and details text for one step"},"Carousel":{"signature":"Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\")","description":"Horizontal scrollable carousel"},"TagBlock":{"signature":"TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")","description":"tags is an array of strings; optional size sm | md | lg"},"Tag":{"signature":"Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")","description":"Styled tag/badge with optional Icon and variant"},"EntityList":{"signature":"EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})","description":"Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers."},"InlineHeader":{"signature":"InlineHeader(heading: string, description?: string)","description":"Compact section heading with an optional one-line description, for use inside cards."},"Icon":{"signature":"Icon(name: string, category?: string)","description":"A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve."},"IconButton":{"signature":"IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")","description":"Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click."},"EditableTable":{"signature":"EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])","description":"Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field"},"ChipItem":{"signature":"ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)","description":"A single selectable chip inside a Chips group, with a value, label and optional icon."},"Chips":{"signature":"Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])","description":"A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`."},"OptionCard":{"signature":"OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)","description":"A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top."},"OptionCards":{"signature":"OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])","description":"A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`."},"Text":{"signature":"Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")","description":"Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"BoldText":{"signature":"BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")","description":"Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"IconText":{"signature":"IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")","description":"An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color."},"ImageText":{"signature":"ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)","description":"A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL."},"ImageTextLarge":{"signature":"ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)","description":"A full-width banner image above a bold title and optional subtitle. src must be a real image URL."},"MetricIndicatorInline":{"signature":"MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})","description":"Headline metric value with an optional +/- percentage trend and subtext, all on one line."},"MetricIndicatorWithStrikethrough":{"signature":"MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})","description":"Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below."},"SnippetCardItem":{"signature":"SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)","description":"One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)."},"SnippetCardBlock":{"signature":"SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action."},"OverviewCardItem":{"signature":"OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)","description":"One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom."},"OverviewCardBlock":{"signature":"OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action."},"ContextCardItem":{"signature":"ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)","description":"A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image."},"ContextCardBlock":{"signature":"ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable."},"CompositeCardItem":{"signature":"CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})","description":"A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer."},"CompositeCardBlock":{"signature":"CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable."},"VisualCardItem":{"signature":"VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)","description":"A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)."},"VisualCardBlock":{"signature":"VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable."}}, +"componentGroups": [{"name":"Content","components":["CardHeader","TextContent","MarkDownRenderer","Callout","TextCallout","Image","ImageBlock","ImageGallery","CodeBlock","Separator","InlineHeader"],"notes":["- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).","- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card."]},{"name":"Tables","components":["Table","Col","EditableTable"],"notes":["- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).","- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes."]},{"name":"Charts (2D)","components":["BarChart","LineChart","AreaChart","RadarChart","HorizontalBarChart","Series"]},{"name":"Charts (1D)","components":["PieChart","RadialChart","SingleStackedBarChart","Slice"]},{"name":"Charts (Scatter)","components":["ScatterChart","ScatterSeries","Point"]},{"name":"Forms","components":["Form","FormControl","Label","Input","TextArea","Select","SelectItem","DatePicker","Slider","CheckBoxGroup","CheckBoxItem","RadioGroup","RadioItem","SwitchGroup","SwitchItem","Chips","ChipItem","OptionCards","OptionCard"],"notes":["- Chips: compact single/multiple selection pills. Use ChipItem references for each option.","- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.","- Define EACH FormControl as its own reference — do NOT inline all controls in one array.","- NEVER nest Form inside Form.","- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).","- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }","- The renderer shows error messages automatically — do NOT generate error text in the UI"]},{"name":"Buttons","components":["Button","Buttons","Icon","IconButton"],"notes":["- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard."]},{"name":"Lists & Follow-ups","components":["ListBlock","ListItem","FollowUpBlock","FollowUpItem"],"notes":["- Use ListBlock with ListItem references for numbered lists.","- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.","- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.","- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.","- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })"]},{"name":"Sections","components":["SectionBlock","SectionItem"],"notes":["- SectionBlock renders collapsible accordion sections that auto-open as they stream.","- Each section needs a unique `value` id, a `trigger` label, and a `content` array.","- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])","- Set isFoldable=false to render sections as flat headers instead of accordion."]},{"name":"Layout","components":["Tabs","TabItem","Accordion","AccordionItem","Steps","StepsItem","Carousel"],"notes":["- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.","- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])","- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.","- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.","- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs."]},{"name":"Data Display","components":["TagBlock","Tag","EntityList"],"notes":["- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not."]},{"name":"Cards","components":["SnippetCardBlock","SnippetCardItem","OverviewCardBlock","OverviewCardItem","ContextCardBlock","ContextCardItem","CompositeCardBlock","CompositeCardItem","VisualCardBlock","VisualCardItem","Text","BoldText","IconText","ImageText","ImageTextLarge","MetricIndicatorInline","MetricIndicatorWithStrikethrough"],"notes":["- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.","- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.","- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.","- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.","- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.","- VisualCardItem: image-first card with a BoldText body and optional Tag.","- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card."]}] } diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/cloud.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/cloud.json index a0394763ea..15077f950e 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/cloud.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/cloud.json @@ -1,379 +1,4 @@ { - "cases": [ - { - "name": "built-in", - "spec": {}, - "expected": "]]>openui:config\n{\"libraryVersion\":\"0.1.0\"}" - }, - { - "name": "built-in-instructions", - "spec": { - "instructions": "Answer in French." - }, - "expected": "]]>openui:config\n{\"libraryVersion\":\"0.1.0\"}\nAnswer in French." - }, - { - "name": "built-in-empty-options", - "spec": { - "promptOptions": { - "preamble": "" - } - }, - "expected": "]]>openui:config\n{\"libraryVersion\":\"0.1.0\"}" - }, - { - "name": "built-in-with-options", - "spec": { - "promptOptions": { - "examples": [] - } - }, - "error": "[generateSystemPrompt] promptOptions requires a library — the built-in library ignores it." - }, - { - "name": "library", - "spec": { - "library": { - "root": "Card", - "components": { - "Card": { - "signature": "Card(children: Text[])" - } - }, - "componentGroups": [ - { - "name": "Layout", - "components": [ - "Card", - "Text" - ], - "notes": [ - "- Note" - ] - } - ], - "schema": { - "$defs": { - "Card": { - "properties": { - "children": { - "type": "array", - "items": { - "$ref": "#/$defs/Text" - } - } - }, - "required": [ - "children" - ] - }, - "Text": { - "properties": { - "value": { - "type": "string" - } - }, - "required": [ - "value" - ] - } - } - } - } - }, - "expected": "]]>openui:config\n{\"chatLibrary\":{\"root\":\"Card\",\"componentGroups\":[{\"name\":\"Layout\",\"components\":[\"Card\",\"Text\"],\"notes\":[\"- Note\"]}],\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}}}}" - }, - { - "name": "library-options", - "spec": { - "library": { - "root": "Card", - "components": { - "Card": { - "signature": "Card(children: Text[])" - } - }, - "componentGroups": [ - { - "name": "Layout", - "components": [ - "Card", - "Text" - ], - "notes": [ - "- Note" - ] - } - ], - "schema": { - "$defs": { - "Card": { - "properties": { - "children": { - "type": "array", - "items": { - "$ref": "#/$defs/Text" - } - } - }, - "required": [ - "children" - ] - }, - "Text": { - "properties": { - "value": { - "type": "string" - } - }, - "required": [ - "value" - ] - } - } - } - }, - "promptOptions": { - "preamble": "Be brief.", - "additionalRules": [ - "One card" - ], - "examples": [ - "a = 1" - ], - "tools": [ - "x" - ], - "editMode": true - }, - "instructions": "Extra." - }, - "expected": "]]>openui:config\n{\"chatLibrary\":{\"root\":\"Card\",\"componentGroups\":[{\"name\":\"Layout\",\"components\":[\"Card\",\"Text\"],\"notes\":[\"- Note\"]}],\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}}},\"systemPromptOptions\":{\"examples\":[\"a = 1\"],\"preamble\":\"Be brief.\",\"additionalRules\":[\"One card\"]}}\nExtra." - }, - { - "name": "library-empty-strings", - "spec": { - "library": { - "root": "Card", - "components": { - "Card": { - "signature": "Card(children: Text[])" - } - }, - "componentGroups": [ - { - "name": "Layout", - "components": [ - "Card", - "Text" - ], - "notes": [ - "- Note" - ] - } - ], - "schema": { - "$defs": { - "Card": { - "properties": { - "children": { - "type": "array", - "items": { - "$ref": "#/$defs/Text" - } - } - }, - "required": [ - "children" - ] - }, - "Text": { - "properties": { - "value": { - "type": "string" - } - }, - "required": [ - "value" - ] - } - } - } - }, - "promptOptions": { - "preamble": "" - }, - "instructions": "" - }, - "expected": "]]>openui:config\n{\"chatLibrary\":{\"root\":\"Card\",\"componentGroups\":[{\"name\":\"Layout\",\"components\":[\"Card\",\"Text\"],\"notes\":[\"- Note\"]}],\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}}}}" - }, - { - "name": "library-without-root", - "spec": { - "library": { - "components": { - "Card": { - "signature": "Card(children: Text[])" - } - }, - "schema": { - "$defs": { - "Card": { - "properties": { - "children": { - "type": "array", - "items": { - "$ref": "#/$defs/Text" - } - } - }, - "required": [ - "children" - ] - }, - "Text": { - "properties": { - "value": { - "type": "string" - } - }, - "required": [ - "value" - ] - } - } - } - } - }, - "expected": "]]>openui:config\n{\"chatLibrary\":{\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}}}}" - }, - { - "name": "library-with-id", - "spec": { - "library": { - "root": "Card", - "components": { - "Card": { - "signature": "Card(children: Text[])" - } - }, - "componentGroups": [ - { - "name": "Layout", - "components": [ - "Card", - "Text" - ], - "notes": [ - "- Note" - ] - } - ], - "schema": { - "$defs": { - "Card": { - "properties": { - "children": { - "type": "array", - "items": { - "$ref": "#/$defs/Text" - } - } - }, - "required": [ - "children" - ] - }, - "Text": { - "properties": { - "value": { - "type": "string" - } - }, - "required": [ - "value" - ] - } - } - }, - "id": "lib-1" - } - }, - "expected": "]]>openui:config\n{\"chatLibrary\":{\"root\":\"Card\",\"componentGroups\":[{\"name\":\"Layout\",\"components\":[\"Card\",\"Text\"],\"notes\":[\"- Note\"]}],\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}},\"id\":\"lib-1\"}}" - }, - { - "name": "broken-library", - "spec": { - "library": { - "root": "Missing", - "components": {}, - "componentGroups": [ - { - "name": "G", - "components": [ - "Card", - "Nope" - ] - }, - { - "name": 1 - } - ], - "schema": { - "$defs": { - "Card": { - "properties": { - "children": { - "type": "array", - "items": { - "$ref": "#/$defs/Gone" - } - }, - "x": { - "$ref": "bad" - } - }, - "required": [ - "children", - "absent", - 3 - ] - }, - "Text": { - "properties": [] - }, - "Bad": "nope" - } - } - } - }, - "error": "[generateSystemPrompt] Invalid library: Root component \"Missing\" was not found in schema.$defs. Available components: Card, Text, Bad. $defs/Card/required must be an array of property names. Unresolvable $ref \"#/$defs/Gone\" at $defs/Card/properties/children/items — refs must be \"#/$defs/\" pointing at a component in $defs. Unresolvable $ref \"bad\" at $defs/Card/properties/x — refs must be \"#/$defs/\" pointing at a component in $defs. $defs/Text/properties must be an object. $defs/Bad must be an object component schema. Component group \"G\" references unknown component \"Nope\". Each componentGroups entry must be {name: string, components: string[], notes?: string[]}." - }, - { - "name": "no-defs", - "spec": { - "library": { - "components": {}, - "schema": { - "$defs": {} - } - } - }, - "error": "[generateSystemPrompt] Invalid library: chatLibrary.schema.$defs must be a non-empty object keyed by component name." - }, - { - "name": "no-schema", - "spec": { - "library": { - "root": "", - "components": {} - } - }, - "error": "[generateSystemPrompt] Invalid library: chatLibrary.root, when present, must be a non-empty string. chatLibrary.schema must be an object with a $defs map of component schemas." - } - ], - "chat": { - "length": 83747, - "sha256": "57e211d92850453a1be46c1e7653d40ec0714b309cef203f4eba589dde7e4f3e" - } +"cases": [{"name":"built-in","spec":{},"expected":"]]>openui:config\n{\"libraryVersion\":\"0.1.0\"}"},{"name":"built-in-instructions","spec":{"instructions":"Answer in French."},"expected":"]]>openui:config\n{\"libraryVersion\":\"0.1.0\"}\nAnswer in French."},{"name":"built-in-empty-options","spec":{"promptOptions":{"preamble":""}},"expected":"]]>openui:config\n{\"libraryVersion\":\"0.1.0\"}"},{"name":"built-in-with-options","spec":{"promptOptions":{"examples":[]}},"error":"[generateSystemPrompt] promptOptions requires a library — the built-in library ignores it."},{"name":"library","spec":{"library":{"root":"Card","components":{"Card":{"signature":"Card(children: Text[])"}},"componentGroups":[{"name":"Layout","components":["Card","Text"],"notes":["- Note"]}],"schema":{"$defs":{"Card":{"properties":{"children":{"type":"array","items":{"$ref":"#/$defs/Text"}}},"required":["children"]},"Text":{"properties":{"value":{"type":"string"}},"required":["value"]}}}}},"expected":"]]>openui:config\n{\"chatLibrary\":{\"root\":\"Card\",\"componentGroups\":[{\"name\":\"Layout\",\"components\":[\"Card\",\"Text\"],\"notes\":[\"- Note\"]}],\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}}}}"},{"name":"library-options","spec":{"library":{"root":"Card","components":{"Card":{"signature":"Card(children: Text[])"}},"componentGroups":[{"name":"Layout","components":["Card","Text"],"notes":["- Note"]}],"schema":{"$defs":{"Card":{"properties":{"children":{"type":"array","items":{"$ref":"#/$defs/Text"}}},"required":["children"]},"Text":{"properties":{"value":{"type":"string"}},"required":["value"]}}}},"promptOptions":{"preamble":"Be brief.","additionalRules":["One card"],"examples":["a = 1"],"tools":["x"],"editMode":true},"instructions":"Extra."},"expected":"]]>openui:config\n{\"chatLibrary\":{\"root\":\"Card\",\"componentGroups\":[{\"name\":\"Layout\",\"components\":[\"Card\",\"Text\"],\"notes\":[\"- Note\"]}],\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}}},\"systemPromptOptions\":{\"examples\":[\"a = 1\"],\"preamble\":\"Be brief.\",\"additionalRules\":[\"One card\"]}}\nExtra."},{"name":"library-empty-strings","spec":{"library":{"root":"Card","components":{"Card":{"signature":"Card(children: Text[])"}},"componentGroups":[{"name":"Layout","components":["Card","Text"],"notes":["- Note"]}],"schema":{"$defs":{"Card":{"properties":{"children":{"type":"array","items":{"$ref":"#/$defs/Text"}}},"required":["children"]},"Text":{"properties":{"value":{"type":"string"}},"required":["value"]}}}},"promptOptions":{"preamble":""},"instructions":""},"expected":"]]>openui:config\n{\"chatLibrary\":{\"root\":\"Card\",\"componentGroups\":[{\"name\":\"Layout\",\"components\":[\"Card\",\"Text\"],\"notes\":[\"- Note\"]}],\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}}}}"},{"name":"library-without-root","spec":{"library":{"components":{"Card":{"signature":"Card(children: Text[])"}},"schema":{"$defs":{"Card":{"properties":{"children":{"type":"array","items":{"$ref":"#/$defs/Text"}}},"required":["children"]},"Text":{"properties":{"value":{"type":"string"}},"required":["value"]}}}}},"expected":"]]>openui:config\n{\"chatLibrary\":{\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}}}}"},{"name":"library-with-id","spec":{"library":{"root":"Card","components":{"Card":{"signature":"Card(children: Text[])"}},"componentGroups":[{"name":"Layout","components":["Card","Text"],"notes":["- Note"]}],"schema":{"$defs":{"Card":{"properties":{"children":{"type":"array","items":{"$ref":"#/$defs/Text"}}},"required":["children"]},"Text":{"properties":{"value":{"type":"string"}},"required":["value"]}}},"id":"lib-1"}},"expected":"]]>openui:config\n{\"chatLibrary\":{\"root\":\"Card\",\"componentGroups\":[{\"name\":\"Layout\",\"components\":[\"Card\",\"Text\"],\"notes\":[\"- Note\"]}],\"schema\":{\"$defs\":{\"Card\":{\"properties\":{\"children\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/Text\"}}},\"required\":[\"children\"]},\"Text\":{\"properties\":{\"value\":{\"type\":\"string\"}},\"required\":[\"value\"]}}},\"id\":\"lib-1\"}}"},{"name":"broken-library","spec":{"library":{"root":"Missing","components":{},"componentGroups":[{"name":"G","components":["Card","Nope"]},{"name":1}],"schema":{"$defs":{"Card":{"properties":{"children":{"type":"array","items":{"$ref":"#/$defs/Gone"}},"x":{"$ref":"bad"}},"required":["children","absent",3]},"Text":{"properties":[]},"Bad":"nope"}}}},"error":"[generateSystemPrompt] Invalid library: Root component \"Missing\" was not found in schema.$defs. Available components: Card, Text, Bad. $defs/Card/required must be an array of property names. Unresolvable $ref \"#/$defs/Gone\" at $defs/Card/properties/children/items — refs must be \"#/$defs/\" pointing at a component in $defs. Unresolvable $ref \"bad\" at $defs/Card/properties/x — refs must be \"#/$defs/\" pointing at a component in $defs. $defs/Text/properties must be an object. $defs/Bad must be an object component schema. Component group \"G\" references unknown component \"Nope\". Each componentGroups entry must be {name: string, components: string[], notes?: string[]}."},{"name":"no-defs","spec":{"library":{"components":{},"schema":{"$defs":{}}}},"error":"[generateSystemPrompt] Invalid library: chatLibrary.schema.$defs must be a non-empty object keyed by component name."},{"name":"no-schema","spec":{"library":{"root":"","components":{}}},"error":"[generateSystemPrompt] Invalid library: chatLibrary.root, when present, must be a non-empty string. chatLibrary.schema must be an object with a $defs map of component schemas."}], +"chat": {"length":83747,"sha256":"57e211d92850453a1be46c1e7653d40ec0714b309cef203f4eba589dde7e4f3e"} } diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/errors.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/errors.json index c9bbb1ab45..742eb95cee 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/errors.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/errors.json @@ -1,119 +1,9 @@ [ - { - "name": "unknown-component", - "input": "root = Card([Mystery(\"a\"), TextContent(\"b\")])", - "expected": [ - { - "source": "parser", - "code": "unknown-component", - "message": "Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, TextContent, MarkDownRenderer, CardHeader, Callout, TextCallout, CodeBlock, Image, ImageBlock, ImageGallery, Separator, HorizontalBarChart, Series, RadarChart, PieChart, RadialChart, SingleStackedBarChart, ScatterChart, ScatterSeries, Point, AreaChart, BarChart, LineChart, Table, Col, TagBlock, Form, Buttons, Button, FormControl, Input, TextArea, Select, SelectItem, DatePicker, Slider, CheckBoxGroup, CheckBoxItem, RadioGroup, RadioItem, Chips, ChipItem, Icon, OptionCards, OptionCard, IconButton, Steps, StepsItem, InlineHeader, EntityList, EditableTable, SnippetCardBlock, SnippetCardItem, IconText, ImageText, Text, BoldText, OverviewCardBlock, OverviewCardItem, MetricIndicatorInline, ContextCardBlock, ContextCardItem, Tag, CompositeCardBlock, CompositeCardItem, ImageTextLarge, ListBlock, ListItem, MetricIndicatorWithStrikethrough, VisualCardBlock, VisualCardItem, FollowUpBlock, FollowUpItem, SectionBlock, SectionItem, Tabs, TabItem, Accordion, AccordionItem, Carousel, Slice, Label, SwitchGroup, SwitchItem", - "component": "Mystery", - "statementId": "root", - "hint": "Available components: Card, CardHeader, TextContent, MarkDownRenderer, Callout, TextCallout, Image, ImageBlock, ImageGallery, CodeBlock, Separator, Table, Col, BarChart, LineChart, AreaChart, RadarChart, HorizontalBarChart, Series, PieChart, RadialChart, SingleStackedBarChart, Slice, ScatterChart, ScatterSeries, Point, Form, FormControl, Label, Input, TextArea, Select, SelectItem, DatePicker, Slider, CheckBoxGroup, CheckBoxItem, RadioGroup, RadioItem, SwitchGroup, SwitchItem, Button, Buttons, ListBlock, ListItem, FollowUpBlock, FollowUpItem, SectionBlock, SectionItem, Tabs, TabItem, Accordion, AccordionItem, Steps, StepsItem, Carousel, TagBlock, Tag, EntityList, InlineHeader, Icon, IconButton, EditableTable, ChipItem, Chips, OptionCard, OptionCards, Text, BoldText, IconText, ImageText, ImageTextLarge, MetricIndicatorInline, MetricIndicatorWithStrikethrough, SnippetCardItem, SnippetCardBlock, OverviewCardItem, OverviewCardBlock, ContextCardItem, ContextCardBlock, CompositeCardItem, CompositeCardBlock, VisualCardItem, VisualCardBlock" - } - ] - }, - { - "name": "missing-required", - "input": "root = Card([TextContent()])", - "expected": [ - { - "source": "parser", - "code": "missing-required", - "message": "missing required field \"/text\" — signature: TextContent(text*: string, size: \"small\"|\"default\"|\"large\"|\"small-heavy\"|\"large-heavy\")", - "component": "TextContent", - "path": "/text", - "statementId": "root", - "hint": "Signature: TextContent(text*, size) — * marks required" - } - ] - }, - { - "name": "null-required", - "input": "root = Card([TextContent(null)])", - "expected": [ - { - "source": "parser", - "code": "null-required", - "message": "required field \"/text\" cannot be null — signature: TextContent(text*: string, size: \"small\"|\"default\"|\"large\"|\"small-heavy\"|\"large-heavy\")", - "component": "TextContent", - "path": "/text", - "statementId": "root", - "hint": "Signature: TextContent(text*, size) — * marks required" - } - ] - }, - { - "name": "inline-reserved", - "input": "root = Card([TextContent(Query(\"get\", {}))])", - "expected": [ - { - "source": "parser", - "code": "inline-reserved", - "message": "Query() must be declared as a top-level statement, not used inline as a value", - "component": "Query", - "statementId": "root", - "hint": "Declare as a top-level statement: myVar = Query(...)" - }, - { - "source": "parser", - "code": "null-required", - "message": "required field \"/text\" cannot be null — signature: TextContent(text*: string, size: \"small\"|\"default\"|\"large\"|\"small-heavy\"|\"large-heavy\")", - "component": "TextContent", - "path": "/text", - "statementId": "root", - "hint": "Signature: TextContent(text*, size) — * marks required" - } - ] - }, - { - "name": "excess-args", - "input": "root = Card([CardHeader(\"a\", \"b\", \"c\", \"d\")])", - "expected": [ - { - "source": "parser", - "code": "excess-args", - "message": "CardHeader takes 2 arg(s), got 4 (2 excess dropped)", - "component": "CardHeader", - "statementId": "root" - } - ] - }, - { - "name": "type-mismatch", - "input": "root = Card([TextContent(42)])", - "expected": [ - { - "source": "parser", - "code": "type-mismatch", - "message": "field \"/text\" expects string but got number", - "component": "TextContent", - "path": "/text", - "statementId": "root" - } - ] - }, - { - "name": "several", - "input": "root = Card([a, b])\na = Foo()\nb = Button()", - "expected": [ - { - "source": "parser", - "code": "unknown-component", - "message": "Unknown component \"Foo\" — not found in catalog or builtins. Available components: Card, TextContent, MarkDownRenderer, CardHeader, Callout, TextCallout, CodeBlock, Image, ImageBlock, ImageGallery, Separator, HorizontalBarChart, Series, RadarChart, PieChart, RadialChart, SingleStackedBarChart, ScatterChart, ScatterSeries, Point, AreaChart, BarChart, LineChart, Table, Col, TagBlock, Form, Buttons, Button, FormControl, Input, TextArea, Select, SelectItem, DatePicker, Slider, CheckBoxGroup, CheckBoxItem, RadioGroup, RadioItem, Chips, ChipItem, Icon, OptionCards, OptionCard, IconButton, Steps, StepsItem, InlineHeader, EntityList, EditableTable, SnippetCardBlock, SnippetCardItem, IconText, ImageText, Text, BoldText, OverviewCardBlock, OverviewCardItem, MetricIndicatorInline, ContextCardBlock, ContextCardItem, Tag, CompositeCardBlock, CompositeCardItem, ImageTextLarge, ListBlock, ListItem, MetricIndicatorWithStrikethrough, VisualCardBlock, VisualCardItem, FollowUpBlock, FollowUpItem, SectionBlock, SectionItem, Tabs, TabItem, Accordion, AccordionItem, Carousel, Slice, Label, SwitchGroup, SwitchItem", - "component": "Foo", - "statementId": "a", - "hint": "Available components: Card, CardHeader, TextContent, MarkDownRenderer, Callout, TextCallout, Image, ImageBlock, ImageGallery, CodeBlock, Separator, Table, Col, BarChart, LineChart, AreaChart, RadarChart, HorizontalBarChart, Series, PieChart, RadialChart, SingleStackedBarChart, Slice, ScatterChart, ScatterSeries, Point, Form, FormControl, Label, Input, TextArea, Select, SelectItem, DatePicker, Slider, CheckBoxGroup, CheckBoxItem, RadioGroup, RadioItem, SwitchGroup, SwitchItem, Button, Buttons, ListBlock, ListItem, FollowUpBlock, FollowUpItem, SectionBlock, SectionItem, Tabs, TabItem, Accordion, AccordionItem, Steps, StepsItem, Carousel, TagBlock, Tag, EntityList, InlineHeader, Icon, IconButton, EditableTable, ChipItem, Chips, OptionCard, OptionCards, Text, BoldText, IconText, ImageText, ImageTextLarge, MetricIndicatorInline, MetricIndicatorWithStrikethrough, SnippetCardItem, SnippetCardBlock, OverviewCardItem, OverviewCardBlock, ContextCardItem, ContextCardBlock, CompositeCardItem, CompositeCardBlock, VisualCardItem, VisualCardBlock" - }, - { - "source": "parser", - "code": "missing-required", - "message": "missing required field \"/label\" — signature: Button(label*: string, action, variant: \"primary\"|\"secondary\"|\"tertiary\", type: \"normal\"|\"destructive\", size: \"extra-small\"|\"small\"|\"medium\"|\"large\")", - "component": "Button", - "path": "/label", - "statementId": "b", - "hint": "Signature: Button(label*, action, variant, type, size) — * marks required" - } - ] - } +{"name":"unknown-component","input":"root = Card([Mystery(\"a\"), TextContent(\"b\")])","expected":[{"source":"parser","code":"unknown-component","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, TextContent, MarkDownRenderer, CardHeader, Callout, TextCallout, CodeBlock, Image, ImageBlock, ImageGallery, Separator, HorizontalBarChart, Series, RadarChart, PieChart, RadialChart, SingleStackedBarChart, ScatterChart, ScatterSeries, Point, AreaChart, BarChart, LineChart, Table, Col, TagBlock, Form, Buttons, Button, FormControl, Input, TextArea, Select, SelectItem, DatePicker, Slider, CheckBoxGroup, CheckBoxItem, RadioGroup, RadioItem, Chips, ChipItem, Icon, OptionCards, OptionCard, IconButton, Steps, StepsItem, InlineHeader, EntityList, EditableTable, SnippetCardBlock, SnippetCardItem, IconText, ImageText, Text, BoldText, OverviewCardBlock, OverviewCardItem, MetricIndicatorInline, ContextCardBlock, ContextCardItem, Tag, CompositeCardBlock, CompositeCardItem, ImageTextLarge, ListBlock, ListItem, MetricIndicatorWithStrikethrough, VisualCardBlock, VisualCardItem, FollowUpBlock, FollowUpItem, SectionBlock, SectionItem, Tabs, TabItem, Accordion, AccordionItem, Carousel, Slice, Label, SwitchGroup, SwitchItem","component":"Mystery","statementId":"root","hint":"Available components: Card, CardHeader, TextContent, MarkDownRenderer, Callout, TextCallout, Image, ImageBlock, ImageGallery, CodeBlock, Separator, Table, Col, BarChart, LineChart, AreaChart, RadarChart, HorizontalBarChart, Series, PieChart, RadialChart, SingleStackedBarChart, Slice, ScatterChart, ScatterSeries, Point, Form, FormControl, Label, Input, TextArea, Select, SelectItem, DatePicker, Slider, CheckBoxGroup, CheckBoxItem, RadioGroup, RadioItem, SwitchGroup, SwitchItem, Button, Buttons, ListBlock, ListItem, FollowUpBlock, FollowUpItem, SectionBlock, SectionItem, Tabs, TabItem, Accordion, AccordionItem, Steps, StepsItem, Carousel, TagBlock, Tag, EntityList, InlineHeader, Icon, IconButton, EditableTable, ChipItem, Chips, OptionCard, OptionCards, Text, BoldText, IconText, ImageText, ImageTextLarge, MetricIndicatorInline, MetricIndicatorWithStrikethrough, SnippetCardItem, SnippetCardBlock, OverviewCardItem, OverviewCardBlock, ContextCardItem, ContextCardBlock, CompositeCardItem, CompositeCardBlock, VisualCardItem, VisualCardBlock"}]}, +{"name":"missing-required","input":"root = Card([TextContent()])","expected":[{"source":"parser","code":"missing-required","message":"missing required field \"/text\" — signature: TextContent(text*: string, size: \"small\"|\"default\"|\"large\"|\"small-heavy\"|\"large-heavy\")","component":"TextContent","path":"/text","statementId":"root","hint":"Signature: TextContent(text*, size) — * marks required"}]}, +{"name":"null-required","input":"root = Card([TextContent(null)])","expected":[{"source":"parser","code":"null-required","message":"required field \"/text\" cannot be null — signature: TextContent(text*: string, size: \"small\"|\"default\"|\"large\"|\"small-heavy\"|\"large-heavy\")","component":"TextContent","path":"/text","statementId":"root","hint":"Signature: TextContent(text*, size) — * marks required"}]}, +{"name":"inline-reserved","input":"root = Card([TextContent(Query(\"get\", {}))])","expected":[{"source":"parser","code":"inline-reserved","message":"Query() must be declared as a top-level statement, not used inline as a value","component":"Query","statementId":"root","hint":"Declare as a top-level statement: myVar = Query(...)"},{"source":"parser","code":"null-required","message":"required field \"/text\" cannot be null — signature: TextContent(text*: string, size: \"small\"|\"default\"|\"large\"|\"small-heavy\"|\"large-heavy\")","component":"TextContent","path":"/text","statementId":"root","hint":"Signature: TextContent(text*, size) — * marks required"}]}, +{"name":"excess-args","input":"root = Card([CardHeader(\"a\", \"b\", \"c\", \"d\")])","expected":[{"source":"parser","code":"excess-args","message":"CardHeader takes 2 arg(s), got 4 (2 excess dropped)","component":"CardHeader","statementId":"root"}]}, +{"name":"type-mismatch","input":"root = Card([TextContent(42)])","expected":[{"source":"parser","code":"type-mismatch","message":"field \"/text\" expects string but got number","component":"TextContent","path":"/text","statementId":"root"}]}, +{"name":"several","input":"root = Card([a, b])\na = Foo()\nb = Button()","expected":[{"source":"parser","code":"unknown-component","message":"Unknown component \"Foo\" — not found in catalog or builtins. Available components: Card, TextContent, MarkDownRenderer, CardHeader, Callout, TextCallout, CodeBlock, Image, ImageBlock, ImageGallery, Separator, HorizontalBarChart, Series, RadarChart, PieChart, RadialChart, SingleStackedBarChart, ScatterChart, ScatterSeries, Point, AreaChart, BarChart, LineChart, Table, Col, TagBlock, Form, Buttons, Button, FormControl, Input, TextArea, Select, SelectItem, DatePicker, Slider, CheckBoxGroup, CheckBoxItem, RadioGroup, RadioItem, Chips, ChipItem, Icon, OptionCards, OptionCard, IconButton, Steps, StepsItem, InlineHeader, EntityList, EditableTable, SnippetCardBlock, SnippetCardItem, IconText, ImageText, Text, BoldText, OverviewCardBlock, OverviewCardItem, MetricIndicatorInline, ContextCardBlock, ContextCardItem, Tag, CompositeCardBlock, CompositeCardItem, ImageTextLarge, ListBlock, ListItem, MetricIndicatorWithStrikethrough, VisualCardBlock, VisualCardItem, FollowUpBlock, FollowUpItem, SectionBlock, SectionItem, Tabs, TabItem, Accordion, AccordionItem, Carousel, Slice, Label, SwitchGroup, SwitchItem","component":"Foo","statementId":"a","hint":"Available components: Card, CardHeader, TextContent, MarkDownRenderer, Callout, TextCallout, Image, ImageBlock, ImageGallery, CodeBlock, Separator, Table, Col, BarChart, LineChart, AreaChart, RadarChart, HorizontalBarChart, Series, PieChart, RadialChart, SingleStackedBarChart, Slice, ScatterChart, ScatterSeries, Point, Form, FormControl, Label, Input, TextArea, Select, SelectItem, DatePicker, Slider, CheckBoxGroup, CheckBoxItem, RadioGroup, RadioItem, SwitchGroup, SwitchItem, Button, Buttons, ListBlock, ListItem, FollowUpBlock, FollowUpItem, SectionBlock, SectionItem, Tabs, TabItem, Accordion, AccordionItem, Steps, StepsItem, Carousel, TagBlock, Tag, EntityList, InlineHeader, Icon, IconButton, EditableTable, ChipItem, Chips, OptionCard, OptionCards, Text, BoldText, IconText, ImageText, ImageTextLarge, MetricIndicatorInline, MetricIndicatorWithStrikethrough, SnippetCardItem, SnippetCardBlock, OverviewCardItem, OverviewCardBlock, ContextCardItem, ContextCardBlock, CompositeCardItem, CompositeCardBlock, VisualCardItem, VisualCardBlock"},{"source":"parser","code":"missing-required","message":"missing required field \"/label\" — signature: Button(label*: string, action, variant: \"primary\"|\"secondary\"|\"tertiary\", type: \"normal\"|\"destructive\", size: \"extra-small\"|\"small\"|\"medium\"|\"large\")","component":"Button","path":"/label","statementId":"b","hint":"Signature: Button(label*, action, variant, type, size) — * marks required"}]} ] diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/evaluation.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/evaluation.json index 10228fda12..d1aeb92666 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/evaluation.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/evaluation.json @@ -1,4740 +1,27 @@ [ - { - "name": "chat-example-1", - "schema": "chat", - "input": "Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "CardHeader", - "props": { - "title": "Paris", - "subtitle": "The City of Light · France's Eternal Capital" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "header" - }, - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]." - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "intro" - }, - { - "type": "element", - "typeName": "ContextCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "ContextCardItem", - "props": { - "id": "art-museums", - "title": "Art & Museums", - "body": "143 museums including the Louvre & newly reopened Grand Palais.", - "bgColor": "gray", - "bgImageSrc": "https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "h1" - }, - { - "type": "element", - "typeName": "ContextCardItem", - "props": { - "id": "gastronomy", - "title": "Gastronomy", - "body": "9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.", - "bgColor": "gray" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "h2" - }, - { - "type": "element", - "typeName": "ContextCardItem", - "props": { - "id": "fashion-capital", - "title": "Fashion Capital", - "body": "Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.", - "bgColor": "gray", - "bgImageSrc": "https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "h3" - } - ], - "layout": "grid", - "responsive": true, - "action": { - "type": "continue_conversation", - "context": "Tell me more about this aspect of Paris" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "highlights" - }, - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "Paris by the Numbers", - "description": "Key visitor statistics" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "statsHeader" - }, - { - "type": "element", - "typeName": "OverviewCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "OverviewCardItem", - "props": { - "id": "annual-visitors", - "top": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "users", - "category": "people" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov1icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Annual Visitors", - "subtitle": "2024 arrivals", - "bold": false, - "layout": "vertical" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov1top" - }, - "bottom": { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "48.7M", - "subtext": "tourists", - "trend": { - "direction": "up", - "value": 2.5 - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov1metric" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov1" - }, - { - "type": "element", - "typeName": "OverviewCardItem", - "props": { - "id": "museums-monuments", - "top": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "landmark", - "category": "buildings" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov2icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Museums & Monuments", - "subtitle": "Cultural sites", - "bold": false, - "layout": "vertical" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov2top" - }, - "bottom": { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "2,370+", - "subtext": "across the city" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov2metric" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov2" - }, - { - "type": "element", - "typeName": "OverviewCardItem", - "props": { - "id": "tourism-revenue", - "top": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "circle-dollar-sign", - "category": "finance" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov3icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Tourism Revenue", - "subtitle": "2024 estimate", - "bold": false, - "layout": "vertical" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov3top" - }, - "bottom": { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "€23.4B", - "subtext": "generated" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov3metric" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov3" - } - ], - "layout": "grid", - "responsive": true - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "statsCards" - }, - { - "type": "element", - "typeName": "SectionBlock", - "props": { - "sections": [ - { - "type": "element", - "typeName": "SectionItem", - "props": { - "value": "landmarks", - "trigger": "Iconic Landmarks", - "content": [ - { - "type": "element", - "typeName": "VisualCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Eiffel Tower", - "subtext": "Open daily 9am–midnight", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm1body" - }, - "id": "eiffel-tower", - "bgImageSrc": "https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "Must-See", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "star", - "category": "shapes" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm1tagIcon" - }, - "size": "sm", - "variant": "info" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm1tag" - }, - "bgImageAlt": "Aerial view of the Eiffel Tower" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm1" - }, - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "The Louvre", - "subtext": "World's largest art museum", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm2body" - }, - "id": "the-louvre", - "bgImageSrc": "https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "8.9M visits/yr", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "trending-up", - "category": "charts" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm2tagIcon" - }, - "size": "sm", - "variant": "success" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm2tag" - }, - "bgImageAlt": "Exterior of the Louvre museum" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm2" - }, - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Notre-Dame", - "subtext": "Fully restored cathedral", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm3body" - }, - "id": "notre-dame", - "bgImageSrc": "https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "Reopened 2024", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "hammer", - "category": "tools" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm3tagIcon" - }, - "size": "sm", - "variant": "warning" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm3tag" - }, - "bgImageAlt": "Notre-Dame cathedral facade" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm3" - }, - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Palace of Versailles", - "subtext": "Royal gardens & grand halls", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm4body" - }, - "id": "versailles", - "bgImageSrc": "https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "Day Trip", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "train-front", - "category": "travel" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm4tagIcon" - }, - "size": "sm", - "variant": "neutral" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm4tag" - }, - "bgImageAlt": "Latona Fountain at Versailles" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm4" - } - ], - "layout": "carousel", - "responsive": true, - "action": { - "type": "continue_conversation", - "context": "Tell me more about this Paris landmark" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "landmarksCarousel" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "secLandmarks" - }, - { - "type": "element", - "typeName": "SectionItem", - "props": { - "value": "food", - "trigger": "Food & Drink", - "content": [ - { - "type": "element", - "typeName": "ContextCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "ContextCardItem", - "props": { - "id": "bistros", - "title": "Bistros", - "body": "Classic French fare — try Les Arlots for confit beef cheeks.", - "bgColor": "gray", - "bgImageSrc": "https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "f1" - }, - { - "type": "element", - "typeName": "ContextCardItem", - "props": { - "id": "fine-dining", - "title": "Fine Dining", - "body": "Septime leads a new wave of creative Michelin-starred cuisine.", - "bgColor": "gray", - "bgImageSrc": "https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "f2" - }, - { - "type": "element", - "typeName": "ContextCardItem", - "props": { - "id": "bakeries", - "title": "Bakeries", - "body": "Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.", - "bgColor": "gray", - "bgImageSrc": "https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "f3" - } - ], - "layout": "grid", - "responsive": true, - "action": { - "type": "continue_conversation", - "context": "Tell me more about eating and drinking in Paris" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "foodCards" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "secFood" - }, - { - "type": "element", - "typeName": "SectionItem", - "props": { - "value": "when", - "trigger": "Best Time to Visit", - "content": [ - { - "type": "element", - "typeName": "Tabs", - "props": { - "items": [ - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "spring", - "trigger": "Spring", - "content": [ - { - "type": "element", - "typeName": "ListBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "ListItem", - "props": { - "title": "Cherry blossoms at Parc de Sceaux", - "subtitle": "March – May", - "image": null, - "actionLabel": null, - "action": { - "type": "continue_conversation", - "context": "Tell me about cherry blossom season in Paris" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "sp1" - }, - { - "type": "element", - "typeName": "ListItem", - "props": { - "title": "Picnics along the Seine & in city parks", - "subtitle": "Warm, lively atmosphere", - "image": null, - "actionLabel": null, - "action": { - "type": "continue_conversation", - "context": "Where are the best picnic spots in Paris?" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "sp2" - }, - { - "type": "element", - "typeName": "ListItem", - "props": { - "title": "Fewer crowds than summer", - "subtitle": "Ideal for sightseeing", - "image": null, - "actionLabel": null, - "action": { - "type": "continue_conversation", - "context": "How busy is Paris in spring?" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "sp3" - } - ], - "variant": "number" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "springList" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabSpring" - }, - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "summer", - "trigger": "Summer", - "content": [ - { - "type": "element", - "typeName": "ListBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "ListItem", - "props": { - "title": "Swim in the Seine — open July & August 2026", - "subtitle": "First time in 102 years", - "image": null, - "actionLabel": null, - "action": { - "type": "continue_conversation", - "context": "Tell me about swimming in the Seine" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "su1" - }, - { - "type": "element", - "typeName": "ListItem", - "props": { - "title": "Open-air cinema at Parc de la Villette", - "subtitle": "Free films under the stars", - "image": null, - "actionLabel": null, - "action": { - "type": "continue_conversation", - "context": "Tell me about the open-air cinema at Parc de la Villette" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "su2" - }, - { - "type": "element", - "typeName": "ListItem", - "props": { - "title": "Bastille Day celebrations on July 14", - "subtitle": "Fireworks at the Eiffel Tower", - "image": null, - "actionLabel": null, - "action": { - "type": "continue_conversation", - "context": "What happens in Paris on Bastille Day?" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "su3" - } - ], - "variant": "number" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "summerList" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabSummer" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "whenTabs" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "secWhen" - } - ], - "isFoldable": false - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "sectionsBlock" - }, - { - "type": "element", - "typeName": "Buttons", - "props": { - "buttons": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Plan a Trip to Paris", - "action": { - "type": "continue_conversation", - "context": "Help me plan a trip to Paris" - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btn1" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Best Hotels in Paris", - "action": { - "type": "continue_conversation", - "context": "Show me the best hotels in Paris" - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btn2" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Build a Paris Itinerary", - "action": { - "type": "continue_conversation", - "context": "Build a 5-day Paris itinerary for me" - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btn3" - } - ], - "direction": "row" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "actionBtns" - } - ], - "sources": [ - { - "title": "Paris Travel Guide 2025", - "sourceName": "Travel and Tour World", - "url": "https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/" - }, - { - "title": "Best Things to Do in Paris 2026", - "sourceName": "Time Out Paris", - "url": "http://www.timeout.fr/paris/en/for-tourists" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "chat-example-2", - "schema": "chat", - "input": "Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "CardHeader", - "props": { - "title": "Analytics Dashboard", - "subtitle": "April 2026 · Business Performance Overview" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "pageHeader" - }, - { - "type": "element", - "typeName": "SnippetCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "total-revenue", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "circle-dollar-sign", - "category": "finance" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Total Revenue", - "subtitle": "Month to date", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "$284,500", - "subtext": "+12.4%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1" - }, - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "active-users", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "users", - "category": "people" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Active Users", - "subtitle": "Monthly active users", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "47,320", - "subtext": "+6.8%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2" - }, - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "conversion-rate", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "trending-up", - "category": "charts" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Conversion Rate", - "subtitle": "Avg. this month", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "5.7%", - "subtext": "+0.9%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3" - }, - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "churn-rate", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "user-minus", - "category": "people" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi4icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Churn Rate", - "subtitle": "Monthly customer churn", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi4lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "2.1%", - "subtext": "-0.4%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi4rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi4" - } - ], - "layout": "grid", - "responsive": true - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpiBlock" - }, - { - "type": "element", - "typeName": "SectionBlock", - "props": { - "sections": [ - { - "type": "element", - "typeName": "SectionItem", - "props": { - "value": "users", - "trigger": "User Activity", - "content": [ - { - "type": "element", - "typeName": "Tabs", - "props": { - "items": [ - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "growth", - "trigger": "User Growth", - "content": [ - { - "type": "element", - "typeName": "LineChart", - "props": { - "labels": [ - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - "Jan", - "Feb", - "Mar", - "Apr" - ], - "series": [ - { - "type": "element", - "typeName": "Series", - "props": { - "category": "DAU", - "values": [ - 5.1, - 5.4, - 5.8, - 6.2, - 6.7, - 7.1, - 7.6, - 8, - 8.4, - 8.9, - 9.3, - 9.8 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "dauSeries" - }, - { - "type": "element", - "typeName": "Series", - "props": { - "category": "MAU", - "values": [ - 28.4, - 30.1, - 31.8, - 33.5, - 35.2, - 37.1, - 38.8, - 40.4, - 42.1, - 43.9, - 45.6, - 47.3 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "mauSeries" - } - ], - "variant": "natural", - "xLabel": "Month", - "yLabel": "Users (k)" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "growthChart" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabGrowth" - }, - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "retention", - "trigger": "Cohort Retention", - "content": [ - { - "type": "element", - "typeName": "LineChart", - "props": { - "labels": [ - "Month 0", - "Month 1", - "Month 2", - "Month 3", - "Month 4", - "Month 5", - "Month 6" - ], - "series": [ - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Jan Cohort", - "values": [ - 100, - 80, - 70, - 62, - 56, - 51, - 47 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "cohortJan" - }, - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Feb Cohort", - "values": [ - 100, - 83, - 73, - 65, - 59, - 54, - 50 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "cohortFeb" - }, - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Mar Cohort", - "values": [ - 100, - 86, - 76, - 68, - 62, - 0, - 0 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "cohortMar" - } - ], - "variant": "natural", - "xLabel": "Month Since Signup", - "yLabel": "Retention (%)" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "retentionChart" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabRetention" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "userTabs" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "secUsers" - }, - { - "type": "element", - "typeName": "SectionItem", - "props": { - "value": "channels", - "trigger": "Acquisition Channels", - "content": [ - { - "type": "element", - "typeName": "Tabs", - "props": { - "items": [ - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "channel-bar", - "trigger": "Revenue by Channel", - "content": [ - { - "type": "element", - "typeName": "HorizontalBarChart", - "props": { - "labels": [ - "Organic Search", - "Paid Ads", - "Referral Program", - "Partner Network", - "Direct / Brand", - "Email Campaigns" - ], - "series": [ - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Revenue ($k)", - "values": [ - 82.4, - 68.1, - 54.6, - 38.2, - 26.8, - 14.4 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "channelSeries" - } - ], - "variant": "grouped", - "xLabel": "Revenue ($k)", - "yLabel": "Channel" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "channelBarChart" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabChannelBar" - }, - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "channel-table", - "trigger": "Full Breakdown", - "content": [ - { - "type": "element", - "typeName": "Table", - "props": { - "columns": [ - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Channel", - "data": [ - "Organic Search", - "Paid Ads", - "Referral Program", - "Partner Network", - "Direct / Brand", - "Email Campaigns" - ], - "type": "string" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "colChannel" - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Leads", - "data": [ - 4210, - 3180, - 2050, - 1120, - 1290, - 820 - ], - "type": "number" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "colLeads" - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Conv. Rate", - "data": [ - "6.4%", - "5.1%", - "9.4%", - "11.8%", - "5.8%", - "8.1%" - ], - "type": "string" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "colConv" - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "CAC ($)", - "data": [ - 188, - 395, - 132, - 109, - 218, - 154 - ], - "type": "number" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "colCac" - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Revenue ($k)", - "data": [ - 82.4, - 68.1, - 54.6, - 38.2, - 26.8, - 14.4 - ], - "type": "number" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "colRevenue" - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Status", - "data": [ - "Scaling", - "Optimizing", - "Scaling", - "Growing", - "Stable", - "Stable" - ], - "type": "string" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "colStatus" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "channelTable" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabChannelTable" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "channelTabs" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "secChannels" - } - ], - "isFoldable": false - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "sections" - }, - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "Support Health & Marketing ROI", - "description": "Click a card to explore deeper insights" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "deepDiveHeader" - }, - { - "type": "element", - "typeName": "CompositeCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "CompositeCardItem", - "props": { - "id": "support-health", - "header": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "headphones", - "category": "communication" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "supportIcon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Support Health", - "subtitle": "Ticket volume & resolution trends", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "supportHeader" - }, - "body": [ - { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "94.2% CSAT", - "subtext": "Customer Satisfaction Score", - "trend": { - "direction": "up", - "value": 2.1 - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "supportMetric" - }, - { - "type": "element", - "typeName": "BarChart", - "props": { - "labels": [ - "Jan", - "Feb", - "Mar", - "Apr" - ], - "series": [ - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Opened", - "values": [ - 341, - 327, - 308, - 289 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "openSeries" - }, - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Resolved", - "values": [ - 319, - 318, - 301, - 283 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "resolvedSeries" - } - ], - "variant": "grouped", - "xLabel": "Month", - "yLabel": "Tickets" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "supportChart" - }, - { - "type": "element", - "typeName": "EntityList", - "props": { - "rows": [ - { - "left": "Avg. Resolution Time", - "right": "4h 12m", - "rightVariant": "text" - }, - { - "left": "First Contact Resolution", - "right": "78.4%", - "rightVariant": "number" - }, - { - "left": "Escalation Rate", - "right": "6.2%", - "rightVariant": "number" - } - ], - "size": "small" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "supportList" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "cardSupport" - }, - { - "type": "element", - "typeName": "CompositeCardItem", - "props": { - "id": "marketing-roi", - "header": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "megaphone", - "category": "communication" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "marketingIcon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Marketing ROI", - "subtitle": "Spend vs. pipeline generated", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "marketingHeader" - }, - "body": [ - { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "3.8x Blended ROI", - "subtext": "Return on Ad Spend", - "trend": { - "direction": "up", - "value": 0.4 - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "marketingMetric" - }, - { - "type": "element", - "typeName": "AreaChart", - "props": { - "labels": [ - "Jan", - "Feb", - "Mar", - "Apr" - ], - "series": [ - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Ad Spend", - "values": [ - 44, - 46.8, - 49.2, - 51.6 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "spendSeries" - }, - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Pipeline Generated", - "values": [ - 158.2, - 171.5, - 184.9, - 196.1 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "pipelineSeries" - } - ], - "variant": "natural", - "xLabel": "Month", - "yLabel": "Value ($k)" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "marketingChart" - }, - { - "type": "element", - "typeName": "EntityList", - "props": { - "rows": [ - { - "left": "Total Ad Spend (Apr)", - "right": "$51,600", - "rightVariant": "number" - }, - { - "left": "Cost per Lead", - "right": "$48.20", - "rightVariant": "number" - }, - { - "left": "Top Channel", - "right": "Organic Search", - "rightVariant": "text" - } - ], - "size": "small" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "marketingList" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "cardMarketing" - } - ], - "layout": "grid", - "responsive": true, - "action": { - "type": "continue_conversation", - "context": "Explore this deep-dive area in more detail" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "compositeCards" - }, - { - "type": "element", - "typeName": "Buttons", - "props": { - "buttons": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Break Down by Channel", - "action": { - "type": "continue_conversation", - "context": "Break down this month's revenue by acquisition channel" - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btnChannels" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Forecast Next Quarter", - "action": { - "type": "continue_conversation", - "context": "Forecast revenue and active users for next quarter" - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btnForecast" - } - ], - "direction": "row" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "actionButtons" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "chat-example-3", - "schema": "chat", - "input": "Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "CardHeader", - "props": { - "title": "Plan Your Trip", - "subtitle": "A few ideas to spark inspiration — then tell me your preferences" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "header" - }, - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Tap a style to jump straight in, or fill the quick form below for a tailored plan." - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "intro" - }, - { - "type": "element", - "typeName": "VisualCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Tropical Beach Escape", - "subtext": "Overwater villas & snorkeling", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp1body" - }, - "id": "inspo-beach", - "bgImageSrc": "https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "Relaxation", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "umbrella", - "category": "travel" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp1icon" - }, - "size": "sm", - "variant": "info" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp1tag" - }, - "bgImageAlt": "Maldives overwater villas" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp1" - }, - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Mountain Adventure", - "subtext": "Trekking & epic views", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp2body" - }, - "id": "inspo-mountain", - "bgImageSrc": "https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "Active", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "mountain", - "category": "nature" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp2icon" - }, - "size": "sm", - "variant": "warning" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp2tag" - }, - "bgImageAlt": "Trekking in the Peruvian Andes" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp2" - } - ], - "layout": "grid", - "responsive": true, - "action": { - "type": "continue_conversation", - "context": "Plan me a trip in this style with destinations, itinerary, and costs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "inspoCards" - }, - { - "type": "element", - "typeName": "Form", - "props": { - "name": "trip-planner", - "buttons": { - "type": "element", - "typeName": "Buttons", - "props": { - "buttons": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Plan My Trip", - "action": { - "type": "continue_conversation", - "context": "Help me plan a trip based on my form submission" - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btnSubmit" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Just Surprise Me", - "action": { - "type": "continue_conversation", - "context": "Skip the form and surprise me with a destination and itinerary" - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btnSkip" - } - ], - "direction": "row" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "formButtons" - }, - "fields": [ - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Destination", - "input": { - "type": "element", - "typeName": "Input", - "props": { - "name": "destination", - "placeholder": "e.g. Tokyo, Japan — or leave blank", - "type": "text" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "destinationInput" - }, - "hint": "Leave blank if you'd like suggestions" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcDestination" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Travel Dates", - "input": { - "type": "element", - "typeName": "DatePicker", - "props": { - "name": "travel-dates", - "mode": "range", - "rules": { - "required": true - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "datesPicker" - }, - "hint": "Select your start and end dates" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcDates" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Number of Travellers", - "input": { - "type": "element", - "typeName": "Select", - "props": { - "name": "num-travellers", - "items": [ - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "1", - "label": "1 — Solo" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tr1" - }, - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "2", - "label": "2 — Couple" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tr2" - }, - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "3-4", - "label": "3–4 People" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tr3" - }, - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "5+", - "label": "5+ People" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tr4" - } - ], - "placeholder": "Select number of travellers", - "rules": { - "required": true - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "travellersSelect" - }, - "hint": "How many people are travelling?" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcTravellers" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Trip Type", - "input": { - "type": "element", - "typeName": "OptionCards", - "props": { - "name": "trip-type", - "type": "single", - "items": [ - { - "type": "element", - "typeName": "OptionCard", - "props": { - "value": "adventure", - "title": "Adventure", - "subtitle": "Hiking, trekking & outdoor activities", - "topContent": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "mountain", - "category": "nature" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc1icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc1" - }, - { - "type": "element", - "typeName": "OptionCard", - "props": { - "value": "beach", - "title": "Beach & Relaxation", - "subtitle": "Sun, sand & leisure", - "topContent": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "waves", - "category": "nature" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc2icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc2" - }, - { - "type": "element", - "typeName": "OptionCard", - "props": { - "value": "cultural", - "title": "Cultural & Historical", - "subtitle": "Museums, heritage & local experiences", - "topContent": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "landmark", - "category": "buildings" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc3icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc3" - }, - { - "type": "element", - "typeName": "OptionCard", - "props": { - "value": "city", - "title": "City Break", - "subtitle": "Urban exploration & nightlife", - "topContent": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "building-2", - "category": "buildings" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc4icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc4" - } - ], - "rules": { - "required": true - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tripTypeCards" - }, - "hint": "What kind of trip are you planning?" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcTripType" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Estimated Budget (per person)", - "input": { - "type": "element", - "typeName": "Slider", - "props": { - "name": "budget", - "variant": "discrete", - "min": 500, - "max": 10000, - "step": 500, - "defaultValue": [ - 2500 - ], - "label": "Budget (USD)" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "budgetSlider" - }, - "hint": "Drag to set your per-person budget in USD" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcBudget" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Accommodation Preference", - "input": { - "type": "element", - "typeName": "Chips", - "props": { - "name": "accommodation", - "type": "multiple", - "items": [ - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "hotel", - "label": "Hotel", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "building", - "category": "buildings" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch1icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch1" - }, - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "resort", - "label": "Resort", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "umbrella", - "category": "travel" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch2icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch2" - }, - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "airbnb", - "label": "Vacation Rental", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "home", - "category": "home" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch3icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch3" - }, - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "camping", - "label": "Camping / Glamping", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "tent", - "category": "nature" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch4icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch4" - } - ], - "rules": {}, - "defaultValue": [ - "hotel" - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "stayChips" - }, - "hint": "Select all that apply" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcStay" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Special Requests or Notes", - "input": { - "type": "element", - "typeName": "TextArea", - "props": { - "name": "special-requests", - "placeholder": "e.g. vegetarian meals, wheelchair access, honeymoon surprise...", - "rows": 4 - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "notesArea" - }, - "hint": "Any dietary needs, accessibility requirements, or specific interests?" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcNotes" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "form" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "chat-example-4", - "schema": "chat", - "input": "Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "CardHeader", - "props": { - "title": "Retro-Energetic Indian Tracks", - "subtitle": "New Hindi releases with 80s/90s dance DNA" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "header" - }, - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video." - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "intro" - }, - { - "type": "element", - "typeName": "VisualCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Tamma Tamma", - "subtext": "Dhurandhar · Ranveer Singh", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v1body" - }, - "id": "tamma", - "bgImageSrc": "https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "80s Electro-Disco", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "disc-3", - "category": "multimedia" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v1icon" - }, - "size": "sm", - "variant": "success" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v1tag" - }, - "bgImageAlt": "Tamma Tamma video poster" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v1" - }, - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Sajan Re", - "subtext": "Nora Fatehi · Badshah", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v2body" - }, - "id": "sajan", - "bgImageSrc": "https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "Synthwave Electro", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "music", - "category": "multimedia" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v2icon" - }, - "size": "sm", - "variant": "info" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v2tag" - }, - "bgImageAlt": "Sajan Re video poster" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v2" - } - ], - "layout": "grid", - "responsive": true, - "action": { - "type": "continue_conversation", - "context": "Tell me more about this track and its retro influences" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "posters" - }, - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "Watch the Exact Videos", - "description": "Each button opens that track's official video" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "linksHeader" - }, - { - "type": "element", - "typeName": "CompositeCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "CompositeCardItem", - "props": { - "id": "t-tamma", - "header": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "disc-3", - "category": "multimedia" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Tamma Tamma", - "subtitle": "Bappi Lahiri classic, electro-funk rework", - "bold": true, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1h" - }, - "body": [ - { - "type": "element", - "typeName": "Text", - "props": { - "variant": "text", - "value": "Heavy analog synths and brass over a fast disco groove.", - "subtext": "Retro Electro-Disco", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1body" - }, - { - "type": "element", - "typeName": "TagBlock", - "props": { - "tags": [ - "2026 Film Hit", - "Peak Party" - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1tags" - } - ], - "footer": { - "button": { - "type": "element", - "typeName": "Button", - "props": { - "label": "Watch on YouTube", - "action": { - "type": "open_url", - "url": "https://www.youtube.com/watch?v=PQHeOb0Q9oo" - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1btn" - } - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1" - }, - { - "type": "element", - "typeName": "CompositeCardItem", - "props": { - "id": "t-sajan", - "header": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "music", - "category": "multimedia" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t2icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Sajan Re", - "subtitle": "Nora Fatehi · Badshah · Sanjoy", - "bold": true, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t2h" - }, - "body": [ - { - "type": "element", - "typeName": "Text", - "props": { - "variant": "text", - "value": "Synthwave melody hooks over a modern club beat.", - "subtext": "Retro-Fusion Electro", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t2body" - }, - { - "type": "element", - "typeName": "TagBlock", - "props": { - "tags": [ - "Club Anthem", - "Nora x Badshah" - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t2tags" - } - ], - "footer": { - "button": { - "type": "element", - "typeName": "Button", - "props": { - "label": "Watch on YouTube", - "action": { - "type": "open_url", - "url": "https://www.youtube.com/watch?v=COUSCnFazzc" - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t2btn" - } - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t2" - } - ], - "layout": "grid", - "responsive": true - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "trackCards" - } - ], - "sources": [ - { - "title": "Tamma Tamma (Full Video) - Dhurandhar", - "sourceName": "YouTube (T-Series)", - "url": "https://www.youtube.com/watch?v=PQHeOb0Q9oo" - }, - { - "title": "Sajan Re (Official Music Video)", - "sourceName": "YouTube (T-Series)", - "url": "https://www.youtube.com/watch?v=COUSCnFazzc" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "chat-example-5", - "schema": "chat", - "input": "Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Top Languages", - "size": "large-heavy" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "title" - }, - { - "type": "element", - "typeName": "Table", - "props": { - "columns": [ - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Language", - "data": [ - "Python", - "JavaScript", - "Java" - ] - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Users (M)", - "data": [ - 15.7, - 14.2, - 12.1 - ] - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Year", - "data": [ - 1991, - 1995, - 1995 - ] - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tbl" - }, - { - "type": "element", - "typeName": "FollowUpBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "FollowUpItem", - "props": { - "text": "Tell me more about Python" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fu1" - }, - { - "type": "element", - "typeName": "FollowUpItem", - "props": { - "text": "Show me a JavaScript comparison" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fu2" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "followUps" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "openui-example-1", - "schema": "openui", - "input": "Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]", - "expected": { - "root": { - "type": "element", - "typeName": "Stack", - "props": { - "children": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Top Languages", - "size": "large-heavy" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "title" - }, - { - "type": "element", - "typeName": "Table", - "props": { - "columns": [ - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Language", - "data": [ - "Python", - "JavaScript", - "Java", - "TypeScript", - "Go" - ] - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Users (M)", - "data": [ - 15.7, - 14.2, - 12.1, - 8.5, - 5.2 - ] - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Year", - "data": [ - 1991, - 1995, - 1995, - 2012, - 2009 - ] - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tbl" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "openui-example-2", - "schema": "openui", - "input": "Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])", - "expected": { - "root": { - "type": "element", - "typeName": "Stack", - "props": { - "children": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Q4 Revenue", - "size": "large-heavy" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "title" - }, - { - "type": "element", - "typeName": "BarChart", - "props": { - "labels": [ - "Oct", - "Nov", - "Dec" - ], - "series": [ - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Product A", - "values": [ - 120, - 150, - 180 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "s1" - }, - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Product B", - "values": [ - 90, - 110, - 140 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "s2" - } - ], - "variant": "grouped" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "chart" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "openui-example-3", - "schema": "openui", - "input": "Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Stack", - "props": { - "children": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Contact Us", - "size": "large-heavy" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "title" - }, - { - "type": "element", - "typeName": "Form", - "props": { - "name": "contact", - "buttons": { - "type": "element", - "typeName": "Buttons", - "props": { - "buttons": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Submit", - "action": { - "steps": [ - { - "type": "continue_conversation", - "message": "Submit" - } - ] - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Cancel", - "action": { - "steps": [ - { - "type": "continue_conversation", - "message": "Cancel" - } - ] - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "btns" - }, - "fields": [ - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Name", - "input": { - "type": "element", - "typeName": "Input", - "props": { - "name": "name", - "placeholder": "Your name", - "type": "text", - "rules": { - "required": true, - "minLength": 2 - } - }, - "partial": false, - "hasDynamicProps": false - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "nameField" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Email", - "input": { - "type": "element", - "typeName": "Input", - "props": { - "name": "email", - "placeholder": "you@example.com", - "type": "email", - "rules": { - "required": true, - "email": true - } - }, - "partial": false, - "hasDynamicProps": false - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "emailField" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Country", - "input": { - "type": "element", - "typeName": "Select", - "props": { - "name": "country", - "items": [ - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "us", - "label": "United States" - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "uk", - "label": "United Kingdom" - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "de", - "label": "Germany" - }, - "partial": false, - "hasDynamicProps": false - } - ], - "placeholder": "Select...", - "rules": { - "required": true - } - }, - "partial": false, - "hasDynamicProps": false - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "countryField" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Message", - "input": { - "type": "element", - "typeName": "TextArea", - "props": { - "name": "message", - "placeholder": "Tell us more...", - "rows": 4, - "rules": { - "required": true, - "minLength": 10 - } - }, - "partial": false, - "hasDynamicProps": false - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "msgField" - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "form" - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "openui-example-4", - "schema": "openui", - "input": "Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]", - "expected": { - "root": { - "type": "element", - "typeName": "Stack", - "props": { - "children": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "React vs Vue", - "size": "large-heavy" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "title" - }, - { - "type": "element", - "typeName": "Tabs", - "props": { - "items": [ - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "react", - "trigger": "React", - "content": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "React is a library by Meta for building UIs." - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Callout", - "props": { - "variant": "info", - "title": "Note", - "description": "React uses JSX syntax." - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabReact" - }, - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "vue", - "trigger": "Vue", - "content": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Vue is a progressive framework by Evan You." - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Callout", - "props": { - "variant": "success", - "title": "Tip", - "description": "Vue has a gentle learning curve." - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabVue" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabs" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "openui-example-5", - "schema": "openui", - "input": "Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")", - "expected": { - "root": { - "type": "element", - "typeName": "Stack", - "props": { - "children": [ - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "This Month", - "description": "Key account metrics" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpiHeader" - }, - { - "type": "element", - "typeName": "SnippetCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "revenue", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "circle-dollar-sign", - "category": "finance" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Revenue", - "subtitle": "Month to date", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "$48,200", - "subtext": "+8.1%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1" - }, - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "active-users", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "users", - "category": "people" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Active Users", - "subtitle": "This month", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "1,204", - "subtext": "+3.4%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2" - }, - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "churn", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "user-minus", - "category": "people" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Churn", - "subtitle": "This month", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "1.8%", - "subtext": "-0.3%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3" - } - ], - "layout": "grid", - "responsive": true - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpiBlock" - }, - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "Top Products", - "description": "By units sold" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "productsHeader" - }, - { - "type": "element", - "typeName": "CompositeCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "CompositeCardItem", - "props": { - "id": "widget-pro", - "header": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "package", - "category": "shopping" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "p1icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Widget Pro", - "subtitle": "Best seller", - "bold": true, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "p1header" - }, - "body": [ - { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "2,410 units", - "subtext": "Sold this month", - "trend": { - "direction": "up", - "value": 12 - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "p1body" - } - ], - "footer": { - "price": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "$29.00", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false - }, - "button": { - "type": "element", - "typeName": "Button", - "props": { - "label": "View Details", - "action": { - "steps": [ - { - "type": "continue_conversation", - "message": "Show details for Widget Pro" - } - ] - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "p1btn" - } - } - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "p1" - }, - { - "type": "element", - "typeName": "CompositeCardItem", - "props": { - "id": "widget-mini", - "header": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "box", - "category": "shopping" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "p2icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Widget Mini", - "subtitle": "New arrival", - "bold": true, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "p2header" - }, - "body": [ - { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "980 units", - "subtext": "Sold this month", - "trend": { - "direction": "up", - "value": 4 - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "p2body" - } - ], - "footer": { - "price": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "$14.00", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false - }, - "button": { - "type": "element", - "typeName": "Button", - "props": { - "label": "View Details", - "action": { - "steps": [ - { - "type": "continue_conversation", - "message": "Show details for Widget Mini" - } - ] - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "p2btn" - } - } - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "p2" - } - ], - "layout": "grid", - "responsive": true - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "productCards" - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "openui-example-6", - "schema": "openui", - "input": "Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Stack", - "props": { - "children": [ - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "Team Roster", - "description": "Click a cell to edit" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tableHeader" - }, - { - "type": "element", - "typeName": "EditableTable", - "props": { - "name": "roster", - "columns": [ - { - "type": "text", - "key": "name", - "header": "Name" - }, - { - "type": "select", - "key": "role", - "header": "Role", - "options": [ - { - "value": "eng", - "label": "Engineering" - }, - { - "value": "design", - "label": "Design" - } - ] - }, - { - "type": "date-single", - "key": "start", - "header": "Start Date" - } - ], - "data": [ - { - "id": "1", - "values": [ - "Alex Kim", - "eng", - "2024-01-15" - ] - }, - { - "id": "2", - "values": [ - "Jamie Lee", - "design", - "2024-03-02" - ] - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "editTable" - }, - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "Preferences", - "description": "Tell us how you like to work" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "formHeader" - }, - { - "type": "element", - "typeName": "Form", - "props": { - "name": "prefs", - "buttons": { - "type": "element", - "typeName": "Buttons", - "props": { - "buttons": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Save", - "action": { - "steps": [ - { - "type": "continue_conversation", - "message": "Save preferences" - } - ] - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "formButtons" - }, - "fields": [ - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Working Style", - "input": { - "type": "element", - "typeName": "OptionCards", - "props": { - "name": "style", - "type": "single", - "items": [ - { - "type": "element", - "typeName": "OptionCard", - "props": { - "value": "focused", - "title": "Deep Focus", - "subtitle": "Long uninterrupted blocks", - "topContent": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "target", - "category": "tools" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "style1icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "style1" - }, - { - "type": "element", - "typeName": "OptionCard", - "props": { - "value": "collab", - "title": "Collaborative", - "subtitle": "Frequent pairing and syncs", - "topContent": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "users", - "category": "people" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "style2icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "style2" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "styleCards" - }, - "hint": "Pick the one that fits best" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fc1" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Tools", - "input": { - "type": "element", - "typeName": "Chips", - "props": { - "name": "tools", - "type": "multiple", - "items": [ - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "figma", - "label": "Figma", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "figma", - "category": "design" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tool1icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tool1" - }, - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "slack", - "label": "Slack", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "message-square", - "category": "communication" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tool2icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tool2" - }, - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "notion", - "label": "Notion", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "notebook", - "category": "text" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tool3icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tool3" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "toolChips" - }, - "hint": "Select all that apply" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fc2" - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "prefsForm" - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "operators", - "schema": "test", - "input": "$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "yes" - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "member-index", - "schema": "test", - "input": "$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "b" - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": [ - "a", - "b" - ] - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": 1 - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "actions", - "schema": "test", - "input": "$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Inc", - "action": { - "steps": [ - { - "type": "set", - "target": "$n", - "valueAST": { - "k": "BinOp", - "op": "+", - "left": { - "k": "StateRef", - "n": "$n" - }, - "right": { - "k": "Num", - "v": 1 - } - } - }, - { - "type": "continue_conversation", - "message": "Bumped", - "context": "ctx" - } - ] - } - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "b1" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Reset", - "action": { - "steps": [ - { - "type": "reset", - "targets": [ - "$n" - ] - } - ] - } - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "b2" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Docs", - "action": { - "steps": [ - { - "type": "open_url", - "url": "https://openui.com" - } - ] - } - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "b3" - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "each", - "schema": "test", - "input": "$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "a" - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": "b" - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "builtins-all", - "schema": "test", - "input": "$n = [5, \"3\", 9, \"x\", true]\n$rows = [{n: \"b\", v: 2}, {n: \"a\", v: 10}, {n: \"c\", v: \"1\"}]\nroot = Card([Text(\"\" + @Count($n) + \"|\" + @Sum($n) + \"|\" + @Avg($n) + \"|\" + @Min($n) + \"|\" + @Max($n) + \"|\" + @First($n) + \"|\" + @Last($n) + \"|\" + @Round(-2.5) + \"|\" + @Round(1.005, 2) + \"|\" + @Abs(-3) + \"|\" + @Floor(1.7) + \"|\" + @Ceil(1.2)), Text(@Sort($rows, \"v\", \"desc\").n + \"\"), Text(@Sort($rows, \"n\").n + \"\"), Text(@Filter($rows, \"v\", \">\", 1).n + \"\"), Text(@Filter($rows, \"n\", \"contains\", \"a\").n + \"\"), Text(@Filter($rows, \"v\", \"==\", \"2\").n + \"\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "5|18|3.6|0|9|5|true|-2|1|3|1|2" - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": "a,b,c" - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": "a,b,c" - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": "b,a" - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": "a" - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": "b" - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "arithmetic-edges", - "schema": "test", - "input": "$z = 0\nroot = Card([Text(\"\" + (5 / $z) + \"|\" + (-7 % 3) + \"|\" + (7 % $z) + \"|\" + (\"a\" + null) + \"|\" + (null + 1) + \"|\" + (true + 1) + \"|\" + (\"5\" * \"2\") + \"|\" + (\"x\" - 1) + \"|\" + (0.1 + 0.2) + \"|\" + (1 / 3))])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "0|-1|0|a|1|2|10|-1|0.30000000000000004|0.3333333333333333" - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "truthiness-and-equality", - "schema": "test", - "input": "$e = \"\"\n$z = 0\n$arr = []\nroot = Card([Text(\"\" + ($e || \"empty\") + \"|\" + ($z && \"no\") + \"|\" + ($arr ? \"arr-truthy\" : \"arr-falsy\") + \"|\" + (1 == \"1\") + \"|\" + (null == 0) + \"|\" + ($missing == null) + \"|\" + !$e)])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "empty|0|arr-truthy|true|false|true|true" - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "ternary-components", - "schema": "test", - "input": "$on = true\nroot = Card([$on ? Text(\"on\", \"l\") : Button(\"off\"), $on ? null : Text(\"hidden\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "on", - "size": "l" - }, - "partial": false, - "hasDynamicProps": true - }, - null - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "ternary-components-off", - "schema": "test", - "input": "$on = true\nroot = Card([$on ? Text(\"on\", \"l\") : Button(\"off\")])", - "state": { - "$on": false - }, - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "off" - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "state-override", - "schema": "test", - "input": "$count = 1\nroot = Card([Text(\"count \" + $count)])", - "state": { - "$count": 41 - }, - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "count 41" - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "reactive-binding", - "schema": "test", - "input": "$v = \"hi\"\nroot = Card([Input(\"name\", $v), Input(\"plain\", \"x\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Input", - "props": { - "name": "name", - "value": { - "__reactive": "assign", - "target": "$v", - "expr": { - "k": "StateRef", - "n": "$value" - } - } - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Input", - "props": { - "name": "plain", - "value": "x" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "reactive-assign", - "schema": "test", - "input": "$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Input", - "props": { - "name": "name", - "value": { - "__reactive": "assign", - "target": "$v", - "expr": { - "k": "StateRef", - "n": "$value" - } - } - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "query-results", - "schema": "test", - "input": "$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])", - "queryResults": { - "users": { - "rows": [ - { - "id": 1 - }, - { - "id": 2 - } - ] - }, - "save": { - "status": "idle" - } - }, - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "2 users" - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Save", - "action": { - "steps": [ - { - "type": "run", - "statementId": "save", - "refType": "mutation" - }, - { - "type": "run", - "statementId": "users", - "refType": "query" - } - ] - } - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - }, - { - "name": "each-actions", - "schema": "test", - "input": "$items = [{id: 1, t: \"a\"}, {id: 2, t: \"b\"}]\n$sel = 0\nroot = Card(@Each($items, it, Button(it.t, Action([@Set($sel, it.id), @ToAssistant(\"Pick \" + it.t)]))))", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "a", - "action": { - "steps": [ - { - "type": "set", - "target": "$sel", - "valueAST": { - "k": "Num", - "v": 1 - } - }, - { - "type": "continue_conversation", - "message": "Pick a" - } - ] - } - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "b", - "action": { - "steps": [ - { - "type": "set", - "target": "$sel", - "valueAST": { - "k": "Num", - "v": 2 - } - }, - { - "type": "continue_conversation", - "message": "Pick b" - } - ] - } - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "errors": [] - } - } +{"name":"chat-example-1","schema":"chat","input":"Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":false,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"springList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":false,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":false,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":false,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":false,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{"type":"continue_conversation","context":"Show me the best hotels in Paris"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn2"},{"type":"element","typeName":"Button","props":{"label":"Build a Paris Itinerary","action":{"type":"continue_conversation","context":"Build a 5-day Paris itinerary for me"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn3"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[{"title":"Paris Travel Guide 2025","sourceName":"Travel and Tour World","url":"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/"},{"title":"Best Things to Do in Paris 2026","sourceName":"Time Out Paris","url":"http://www.timeout.fr/paris/en/for-tourists"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"errors":[]}}, +{"name":"chat-example-2","schema":"chat","input":"Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":false,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":false,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":false,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":false,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Cost per Lead","right":"$48.20","rightVariant":"number"},{"left":"Top Channel","right":"Organic Search","rightVariant":"text"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Break Down by Channel","action":{"type":"continue_conversation","context":"Break down this month's revenue by acquisition channel"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnChannels"},{"type":"element","typeName":"Button","props":{"label":"Forecast Next Quarter","action":{"type":"continue_conversation","context":"Forecast revenue and active users for next quarter"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnForecast"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionButtons"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"errors":[]}}, +{"name":"chat-example-3","schema":"chat","input":"Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":false,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":false,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":{"type":"element","typeName":"Icon","props":{"name":"home","category":"home"},"partial":false,"hasDynamicProps":false,"statementId":"ch3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch3"},{"type":"element","typeName":"ChipItem","props":{"value":"camping","label":"Camping / Glamping","icon":{"type":"element","typeName":"Icon","props":{"name":"tent","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"ch4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch4"}],"rules":{},"defaultValue":["hotel"]},"partial":false,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fcStay"},{"type":"element","typeName":"FormControl","props":{"label":"Special Requests or Notes","input":{"type":"element","typeName":"TextArea","props":{"name":"special-requests","placeholder":"e.g. vegetarian meals, wheelchair access, honeymoon surprise...","rows":4},"partial":false,"hasDynamicProps":false,"statementId":"notesArea"},"hint":"Any dietary needs, accessibility requirements, or specific interests?"},"partial":false,"hasDynamicProps":false,"statementId":"fcNotes"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"errors":[]}}, +{"name":"chat-example-4","schema":"chat","input":"Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":false,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":false,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},{"title":"Sajan Re (Official Music Video)","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=COUSCnFazzc"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"errors":[]}}, +{"name":"chat-example-5","schema":"chat","input":"Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"},{"type":"element","typeName":"FollowUpItem","props":{"text":"Show me a JavaScript comparison"},"partial":false,"hasDynamicProps":false,"statementId":"fu2"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"errors":[]}}, +{"name":"openui-example-1","schema":"openui","input":"Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]","expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript","Go"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1,8.5,5.2]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995,2012,2009]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"errors":[]}}, +{"name":"openui-example-2","schema":"openui","input":"Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])","expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[{"type":"element","typeName":"Series","props":{"category":"Product A","values":[120,150,180]},"partial":false,"hasDynamicProps":false,"statementId":"s1"},{"type":"element","typeName":"Series","props":{"category":"Product B","values":[90,110,140]},"partial":false,"hasDynamicProps":false,"statementId":"s2"}],"variant":"grouped"},"partial":false,"hasDynamicProps":false,"statementId":"chart"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"errors":[]}}, +{"name":"openui-example-3","schema":"openui","input":"Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])","expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Form","props":{"name":"contact","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Submit","action":{"steps":[{"type":"continue_conversation","message":"Submit"}]},"variant":"primary"},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Cancel","action":{"steps":[{"type":"continue_conversation","message":"Cancel"}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"btns"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Name","input":{"type":"element","typeName":"Input","props":{"name":"name","placeholder":"Your name","type":"text","rules":{"required":true,"minLength":2}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"nameField"},{"type":"element","typeName":"FormControl","props":{"label":"Email","input":{"type":"element","typeName":"Input","props":{"name":"email","placeholder":"you@example.com","type":"email","rules":{"required":true,"email":true}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"emailField"},{"type":"element","typeName":"FormControl","props":{"label":"Country","input":{"type":"element","typeName":"Select","props":{"name":"country","items":[{"type":"element","typeName":"SelectItem","props":{"value":"us","label":"United States"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"uk","label":"United Kingdom"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"de","label":"Germany"},"partial":false,"hasDynamicProps":false}],"placeholder":"Select...","rules":{"required":true}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"countryField"},{"type":"element","typeName":"FormControl","props":{"label":"Message","input":{"type":"element","typeName":"TextArea","props":{"name":"message","placeholder":"Tell us more...","rows":4,"rules":{"required":true,"minLength":10}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"msgField"}]},"partial":false,"hasDynamicProps":true,"statementId":"form"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"openui-example-4","schema":"openui","input":"Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]","expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[{"type":"element","typeName":"TextContent","props":{"text":"Vue is a progressive framework by Evan You."},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"success","title":"Tip","description":"Vue has a gentle learning curve."},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"errors":[]}}, +{"name":"openui-example-5","schema":"openui","input":"Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")","expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":false,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":false,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"steps":[{"type":"continue_conversation","message":"Show details for Widget Pro"}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":false,"hasDynamicProps":true,"statementId":"p1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-mini","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"box","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p2icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Mini","subtitle":"New arrival","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p2header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"980 units","subtext":"Sold this month","trend":{"direction":"up","value":4}},"partial":false,"hasDynamicProps":false,"statementId":"p2body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$14.00","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"steps":[{"type":"continue_conversation","message":"Show details for Widget Mini"}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true,"statementId":"p2btn"}}},"partial":false,"hasDynamicProps":true,"statementId":"p2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"openui-example-6","schema":"openui","input":"Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])","expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":false,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":false,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":false,"hasDynamicProps":false,"statementId":"formHeader"},{"type":"element","typeName":"Form","props":{"name":"prefs","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Save","action":{"steps":[{"type":"continue_conversation","message":"Save preferences"}]},"variant":"primary"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Working Style","input":{"type":"element","typeName":"OptionCards","props":{"name":"style","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"focused","title":"Deep Focus","subtitle":"Long uninterrupted blocks","topContent":{"type":"element","typeName":"Icon","props":{"name":"target","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"style1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"style1"},{"type":"element","typeName":"OptionCard","props":{"value":"collab","title":"Collaborative","subtitle":"Frequent pairing and syncs","topContent":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"style2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"style2"}]},"partial":false,"hasDynamicProps":false,"statementId":"styleCards"},"hint":"Pick the one that fits best"},"partial":false,"hasDynamicProps":false,"statementId":"fc1"},{"type":"element","typeName":"FormControl","props":{"label":"Tools","input":{"type":"element","typeName":"Chips","props":{"name":"tools","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"figma","label":"Figma","icon":{"type":"element","typeName":"Icon","props":{"name":"figma","category":"design"},"partial":false,"hasDynamicProps":false,"statementId":"tool1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool1"},{"type":"element","typeName":"ChipItem","props":{"value":"slack","label":"Slack","icon":{"type":"element","typeName":"Icon","props":{"name":"message-square","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"tool2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool2"},{"type":"element","typeName":"ChipItem","props":{"value":"notion","label":"Notion","icon":{"type":"element","typeName":"Icon","props":{"name":"notebook","category":"text"},"partial":false,"hasDynamicProps":false,"statementId":"tool3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool3"}]},"partial":false,"hasDynamicProps":false,"statementId":"toolChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fc2"}]},"partial":false,"hasDynamicProps":true,"statementId":"prefsForm"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"operators","schema":"test","input":"$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"yes"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"member-index","schema":"test","input":"$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":["a","b"]},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":1},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"actions","schema":"test","input":"$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"steps":[{"type":"set","target":"$n","valueAST":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}},{"type":"continue_conversation","message":"Bumped","context":"ctx"}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"steps":[{"type":"reset","targets":["$n"]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"steps":[{"type":"open_url","url":"https://openui.com"}]}},"partial":false,"hasDynamicProps":true,"statementId":"b3"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"each","schema":"test","input":"$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"builtins-all","schema":"test","input":"$n = [5, \"3\", 9, \"x\", true]\n$rows = [{n: \"b\", v: 2}, {n: \"a\", v: 10}, {n: \"c\", v: \"1\"}]\nroot = Card([Text(\"\" + @Count($n) + \"|\" + @Sum($n) + \"|\" + @Avg($n) + \"|\" + @Min($n) + \"|\" + @Max($n) + \"|\" + @First($n) + \"|\" + @Last($n) + \"|\" + @Round(-2.5) + \"|\" + @Round(1.005, 2) + \"|\" + @Abs(-3) + \"|\" + @Floor(1.7) + \"|\" + @Ceil(1.2)), Text(@Sort($rows, \"v\", \"desc\").n + \"\"), Text(@Sort($rows, \"n\").n + \"\"), Text(@Filter($rows, \"v\", \">\", 1).n + \"\"), Text(@Filter($rows, \"n\", \"contains\", \"a\").n + \"\"), Text(@Filter($rows, \"v\", \"==\", \"2\").n + \"\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"5|18|3.6|0|9|5|true|-2|1|3|1|2"},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":"a,b,c"},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":"a,b,c"},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":"b,a"},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"arithmetic-edges","schema":"test","input":"$z = 0\nroot = Card([Text(\"\" + (5 / $z) + \"|\" + (-7 % 3) + \"|\" + (7 % $z) + \"|\" + (\"a\" + null) + \"|\" + (null + 1) + \"|\" + (true + 1) + \"|\" + (\"5\" * \"2\") + \"|\" + (\"x\" - 1) + \"|\" + (0.1 + 0.2) + \"|\" + (1 / 3))])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"0|-1|0|a|1|2|10|-1|0.30000000000000004|0.3333333333333333"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"truthiness-and-equality","schema":"test","input":"$e = \"\"\n$z = 0\n$arr = []\nroot = Card([Text(\"\" + ($e || \"empty\") + \"|\" + ($z && \"no\") + \"|\" + ($arr ? \"arr-truthy\" : \"arr-falsy\") + \"|\" + (1 == \"1\") + \"|\" + (null == 0) + \"|\" + ($missing == null) + \"|\" + !$e)])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"empty|0|arr-truthy|true|false|true|true"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"ternary-components","schema":"test","input":"$on = true\nroot = Card([$on ? Text(\"on\", \"l\") : Button(\"off\"), $on ? null : Text(\"hidden\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"on","size":"l"},"partial":false,"hasDynamicProps":true},null]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"ternary-components-off","schema":"test","input":"$on = true\nroot = Card([$on ? Text(\"on\", \"l\") : Button(\"off\")])","state":{"$on":false},"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"off"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"state-override","schema":"test","input":"$count = 1\nroot = Card([Text(\"count \" + $count)])","state":{"$count":41},"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"count 41"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"reactive-binding","schema":"test","input":"$v = \"hi\"\nroot = Card([Input(\"name\", $v), Input(\"plain\", \"x\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"__reactive":"assign","target":"$v","expr":{"k":"StateRef","n":"$value"}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Input","props":{"name":"plain","value":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"reactive-assign","schema":"test","input":"$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"__reactive":"assign","target":"$v","expr":{"k":"StateRef","n":"$value"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"query-results","schema":"test","input":"$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])","queryResults":{"users":{"rows":[{"id":1},{"id":2}]},"save":{"status":"idle"}},"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"2 users"},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"steps":[{"type":"run","statementId":"save","refType":"mutation"},{"type":"run","statementId":"users","refType":"query"}]}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}}, +{"name":"each-actions","schema":"test","input":"$items = [{id: 1, t: \"a\"}, {id: 2, t: \"b\"}]\n$sel = 0\nroot = Card(@Each($items, it, Button(it.t, Action([@Set($sel, it.id), @ToAssistant(\"Pick \" + it.t)]))))","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"a","action":{"steps":[{"type":"set","target":"$sel","valueAST":{"k":"Num","v":1}},{"type":"continue_conversation","message":"Pick a"}]}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"b","action":{"steps":[{"type":"set","target":"$sel","valueAST":{"k":"Num","v":2}},{"type":"continue_conversation","message":"Pick b"}]}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"errors":[]}} ] diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/merge.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/merge.json index 1cd7ad7630..dd0d3392e4 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/merge.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/merge.json @@ -1,117 +1,21 @@ [ - { - "name": "empty-existing", - "existing": "", - "patch": "root = Card([a])\na = TextContent(\"x\")", - "expected": "root = Card([a])\na = TextContent(\"x\")" - }, - { - "name": "empty-patch", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", - "patch": " \n", - "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" - }, - { - "name": "replace", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", - "patch": "title = TextContent(\"Q4\", \"large\")", - "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q4\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" - }, - { - "name": "add-referenced", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", - "patch": "root = Card([title, body, note])\nnote = Callout(\"info\", \"Hi\")", - "expected": "root = Card([title, body, note])\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"\nnote = Callout(\"info\", \"Hi\")" - }, - { - "name": "add-unreferenced", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", - "patch": "orphan = TextContent(\"never shown\")", - "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" - }, - { - "name": "delete", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", - "patch": "body = null\nroot = Card([title])", - "expected": "root = Card([title])\ntitle = TextContent(\"Q3\", \"large\")\n$filter = \"all\"" - }, - { - "name": "gc-after-replace", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", - "patch": "body = TextContent(\"no table\")", - "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = TextContent(\"no table\")\n$filter = \"all\"" - }, - { - "name": "keeps-unused-state", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", - "patch": "root = Card([title])\n$extra = 1", - "expected": "root = Card([title])\ntitle = TextContent(\"Q3\", \"large\")\n$filter = \"all\"\n$extra = 1" - }, - { - "name": "root-deleted", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", - "patch": "root = null", - "expected": "title = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" - }, - { - "name": "fenced-patch", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", - "patch": "```openui\ntitle = TextContent(\"Fenced\")\n```", - "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Fenced\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" - }, - { - "name": "multiline-and-strings", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", - "patch": "body = Table([\n colA,\n colB\n])\ntitle = TextContent(\"a ) ] } \\\" ' \\n\", \"large\")", - "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"a ) ] } \\\" ' \\n\", \"large\")\nbody = Table([\n colA,\n colB\n])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" - }, - { - "name": "single-quotes", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", - "patch": "title = TextContent('it\\'s (fine')", - "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent('it\\'s (fine')\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" - }, - { - "name": "crlf", - "existing": "root = Card([title, body, $filter], \"Report\")\r\ntitle = TextContent(\"Q3\", \"large\")\r\nbody = Table([colA, colB])\r\ncolA = Col(\"Region\", [\"EU\", \"US\"])\r\ncolB = Col(\"Revenue\", [1, 2])\r\n$filter = \"all\"", - "patch": "title = TextContent(\"CRLF\")\r\n", - "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"CRLF\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" - }, - { - "name": "duplicate-existing", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"\ntitle = TextContent(\"dup\")", - "patch": "colA = Col(\"Area\", [])", - "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"dup\")\nbody = Table([colA, colB])\ncolA = Col(\"Area\", [])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"\ntitle = TextContent(\"dup\")" - }, - { - "name": "delete-then-add", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", - "patch": "title = null\ntitle = TextContent(\"back\")", - "expected": "root = Card([title, body, $filter], \"Report\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"\ntitle = TextContent(\"back\")" - }, - { - "name": "query-refs", - "existing": "root = Card([t])\nt = Table([c])\nc = Col(\"n\", q.rows)\nq = Query(\"list\", {}, {rows: []})", - "patch": "c = Col(\"name\", q.rows)", - "expected": "root = Card([t])\nt = Table([c])\nc = Col(\"name\", q.rows)\nq = Query(\"list\", {}, {rows: []})" - }, - { - "name": "custom-root", - "existing": "main = Card([a])\na = TextContent(\"x\")\nb = TextContent(\"y\")", - "patch": "a = TextContent(\"z\")", - "rootId": "main", - "expected": "main = Card([a])\na = TextContent(\"z\")" - }, - { - "name": "unclosed-patch", - "existing": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"", - "patch": "title = TextContent(\"cut", - "expected": "root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"cut\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"" - }, - { - "name": "chat-example", - "existing": "Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }", - "patch": "header = CardHeader(\"Edited\", \"by a patch\")", - "expected": "root = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Edited\", \"by a patch\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }" - } +{"name":"empty-existing","existing":"","patch":"root = Card([a])\na = TextContent(\"x\")","expected":"root = Card([a])\na = TextContent(\"x\")"}, +{"name":"empty-patch","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"","patch":" \n","expected":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\""}, +{"name":"replace","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"","patch":"title = TextContent(\"Q4\", \"large\")","expected":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q4\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\""}, +{"name":"add-referenced","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"","patch":"root = Card([title, body, note])\nnote = Callout(\"info\", \"Hi\")","expected":"root = Card([title, body, note])\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"\nnote = Callout(\"info\", \"Hi\")"}, +{"name":"add-unreferenced","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"","patch":"orphan = TextContent(\"never shown\")","expected":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\""}, +{"name":"delete","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"","patch":"body = null\nroot = Card([title])","expected":"root = Card([title])\ntitle = TextContent(\"Q3\", \"large\")\n$filter = \"all\""}, +{"name":"gc-after-replace","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"","patch":"body = TextContent(\"no table\")","expected":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = TextContent(\"no table\")\n$filter = \"all\""}, +{"name":"keeps-unused-state","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"","patch":"root = Card([title])\n$extra = 1","expected":"root = Card([title])\ntitle = TextContent(\"Q3\", \"large\")\n$filter = \"all\"\n$extra = 1"}, +{"name":"root-deleted","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"","patch":"root = null","expected":"title = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\""}, +{"name":"fenced-patch","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"","patch":"```openui\ntitle = TextContent(\"Fenced\")\n```","expected":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Fenced\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\""}, +{"name":"multiline-and-strings","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"","patch":"body = Table([\n colA,\n colB\n])\ntitle = TextContent(\"a ) ] } \\\" ' \\n\", \"large\")","expected":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"a ) ] } \\\" ' \\n\", \"large\")\nbody = Table([\n colA,\n colB\n])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\""}, +{"name":"single-quotes","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"","patch":"title = TextContent('it\\'s (fine')","expected":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent('it\\'s (fine')\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\""}, +{"name":"crlf","existing":"root = Card([title, body, $filter], \"Report\")\r\ntitle = TextContent(\"Q3\", \"large\")\r\nbody = Table([colA, colB])\r\ncolA = Col(\"Region\", [\"EU\", \"US\"])\r\ncolB = Col(\"Revenue\", [1, 2])\r\n$filter = \"all\"","patch":"title = TextContent(\"CRLF\")\r\n","expected":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"CRLF\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\""}, +{"name":"duplicate-existing","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"\ntitle = TextContent(\"dup\")","patch":"colA = Col(\"Area\", [])","expected":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"dup\")\nbody = Table([colA, colB])\ncolA = Col(\"Area\", [])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"\ntitle = TextContent(\"dup\")"}, +{"name":"delete-then-add","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"","patch":"title = null\ntitle = TextContent(\"back\")","expected":"root = Card([title, body, $filter], \"Report\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"\ntitle = TextContent(\"back\")"}, +{"name":"query-refs","existing":"root = Card([t])\nt = Table([c])\nc = Col(\"n\", q.rows)\nq = Query(\"list\", {}, {rows: []})","patch":"c = Col(\"name\", q.rows)","expected":"root = Card([t])\nt = Table([c])\nc = Col(\"name\", q.rows)\nq = Query(\"list\", {}, {rows: []})"}, +{"name":"custom-root","existing":"main = Card([a])\na = TextContent(\"x\")\nb = TextContent(\"y\")","patch":"a = TextContent(\"z\")","rootId":"main","expected":"main = Card([a])\na = TextContent(\"z\")"}, +{"name":"unclosed-patch","existing":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"Q3\", \"large\")\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\"","patch":"title = TextContent(\"cut","expected":"root = Card([title, body, $filter], \"Report\")\ntitle = TextContent(\"cut\nbody = Table([colA, colB])\ncolA = Col(\"Region\", [\"EU\", \"US\"])\ncolB = Col(\"Revenue\", [1, 2])\n$filter = \"all\""}, +{"name":"chat-example","existing":"Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }","patch":"header = CardHeader(\"Edited\", \"by a patch\")","expected":"root = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Edited\", \"by a patch\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }"} ] diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/messages.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/messages.json index 9d86001acf..15df201b09 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/messages.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/messages.json @@ -1,374 +1,6 @@ { - "separate": [ - { - "name": "empty", - "input": "", - "expected": { - "content": "", - "contextString": null - } - }, - { - "name": "plain text", - "input": "Just some text", - "expected": { - "content": "Just some text", - "contextString": null - } - }, - { - "name": "content only", - "input": "]]>openui:content\nroot = Card([])", - "expected": { - "content": "root = Card([])", - "contextString": null, - "contentHeader": "]]>openui:content" - } - }, - { - "name": "content with header attrs", - "input": "]]>openui:content?thesys=true&libraryVersion=0.1.0\nroot = Card([])", - "expected": { - "content": "root = Card([])", - "contextString": null, - "contentHeader": "]]>openui:content?thesys=true&libraryVersion=0.1.0" - } - }, - { - "name": "content and context", - "input": "]]>openui:content\nroot = Card([])\n]]>openui:context\n[{\"f\":1}]", - "expected": { - "content": "root = Card([])", - "contextString": "[{\"f\":1}]", - "contentHeader": "]]>openui:content" - } - }, - { - "name": "context only", - "input": "Hello\n]]>openui:context\n[\"User clicked: Go\"]", - "expected": { - "content": "Hello", - "contextString": "[\"User clicked: Go\"]" - } - }, - { - "name": "context then content", - "input": "]]>openui:context\n[1]\n]]>openui:content\nroot = X()", - "expected": { - "content": "root = X()", - "contextString": null, - "contentHeader": "]]>openui:content" - } - }, - { - "name": "last content wins", - "input": "]]>openui:content\nold\n]]>openui:content\nnew", - "expected": { - "content": "new", - "contextString": null, - "contentHeader": "]]>openui:content" - } - }, - { - "name": "crlf separators", - "input": "]]>openui:content\r\nroot = X()\r\n]]>openui:context\r\n[1]", - "expected": { - "content": "root = X()", - "contextString": "[1]", - "contentHeader": "]]>openui:content\r" - } - }, - { - "name": "end marker", - "input": "]]>openui:content\nroot = X()\n]]>openui:end", - "expected": { - "content": "root = X()", - "contextString": null, - "contentHeader": "]]>openui:content", - "end": true - } - }, - { - "name": "end marker with attrs", - "input": "]]>openui:content\nroot = X()\n]]>openui:end?status=done", - "expected": { - "content": "root = X()", - "contextString": null, - "contentHeader": "]]>openui:content", - "end": true - } - }, - { - "name": "text after end marker", - "input": "]]>openui:content\nroot = X()\n]]>openui:end\ntrailing", - "expected": { - "content": "root = X()\ntrailing", - "contextString": null, - "contentHeader": "]]>openui:content", - "end": true - } - }, - { - "name": "end between sections", - "input": "]]>openui:content\na\n]]>openui:end\n]]>openui:context\n[1]", - "expected": { - "content": "a", - "contextString": "[1]", - "contentHeader": "]]>openui:content", - "end": true - } - }, - { - "name": "two end markers", - "input": "]]>openui:content\na\n]]>openui:end\n]]>openui:end", - "expected": { - "content": "a", - "contextString": null, - "contentHeader": "]]>openui:content", - "end": true - } - }, - { - "name": "crlf before end", - "input": "]]>openui:content\na\r\n]]>openui:end", - "expected": { - "content": "a", - "contextString": null, - "contentHeader": "]]>openui:content", - "end": true - } - }, - { - "name": "partial tail one char", - "input": "]]>openui:content\nroot = X()\n]", - "expected": { - "content": "root = X()", - "contextString": null, - "contentHeader": "]]>openui:content" - } - }, - { - "name": "partial tail sentinel", - "input": "]]>openui:content\nroot = X()\n]]>openui:", - "expected": { - "content": "root = X()", - "contextString": null, - "contentHeader": "]]>openui:content" - } - }, - { - "name": "partial context marker", - "input": "]]>openui:content\nroot = X()\n]]>openui:cont", - "expected": { - "content": "root = X()", - "contextString": null, - "contentHeader": "]]>openui:content" - } - }, - { - "name": "partial end marker", - "input": "]]>openui:content\nroot = X()\n]]>openui:e", - "expected": { - "content": "root = X()", - "contextString": null, - "contentHeader": "]]>openui:content" - } - }, - { - "name": "bracket that isn't a marker", - "input": "]]>openui:content\nx = [1, 2]", - "expected": { - "content": "x = [1, 2", - "contextString": null, - "contentHeader": "]]>openui:content" - } - }, - { - "name": "marker header without newline", - "input": "]]>openui:content", - "expected": { - "content": "", - "contextString": null, - "contentHeader": "]]>openui:content" - } - }, - { - "name": "markers on one line", - "input": "]]>openui:content]]>openui:context\n[1]", - "expected": { - "content": "", - "contextString": "[1]", - "contentHeader": "]]>openui:content]]>openui:context" - } - }, - { - "name": "emoji", - "input": "]]>openui:content\nroot = TextContent(\"🙂 hi\")\n]]>openui:context\n[\"🎉\"]", - "expected": { - "content": "root = TextContent(\"🙂 hi\")", - "contextString": "[\"🎉\"]", - "contentHeader": "]]>openui:content" - } - }, - { - "name": "legacy xml", - "input": "root = X()\n[{\"a\":1}]", - "expected": { - "content": "root = X()", - "contextString": "[{\"a\":1}]" - } - }, - { - "name": "legacy content only", - "input": "root = X() ", - "expected": { - "content": "root = X()", - "contextString": null - } - }, - { - "name": "legacy context only", - "input": "text\n[\"x\"]\n", - "expected": { - "content": "text", - "contextString": "[\"x\"]" - } - }, - { - "name": "legacy unclosed", - "input": "root = X()", - "expected": { - "content": "root = X()", - "contextString": null - } - }, - { - "name": "legacy text after context", - "input": "[1] more", - "expected": { - "content": "[1] more", - "contextString": null - } - } - ], - "langSyntax": [ - { - "input": "```openui-lang\nroot = X()\n```", - "expected": true - }, - { - "input": "root = X()", - "expected": true - }, - { - "input": "root=X()", - "expected": true - }, - { - "input": " root = X()", - "expected": true - }, - { - "input": "intro\n\troot = X()", - "expected": true - }, - { - "input": "intro\n\n root\n= X()", - "expected": true - }, - { - "input": "rooted = 1", - "expected": false - }, - { - "input": "x root = 1", - "expected": false - }, - { - "input": "Just text", - "expected": false - }, - { - "input": "", - "expected": false - } - ], - "artifacts": [ - { - "input": "]]>openui:artifact {\"artifact_id\":\"a1\",\"type\":\"slides\",\"name\":\"Deck\",\"version\":\"2\"}\nroot = X()", - "expected": { - "header": { - "artifact_id": "a1", - "type": "slides", - "name": "Deck", - "version": "2" - }, - "program": "root = X()" - } - }, - { - "input": "]]>openui:artifact {\"artifact_id\":\"a2\",\"type\":\"presentation\"}\nprogram", - "expected": { - "header": { - "artifact_id": "a2", - "type": "slides" - }, - "program": "program" - } - }, - { - "input": "]]>openui:artifact {\"artifact_id\":\"a3\",\"type\":\"report\",\"name\":\"\"}", - "expected": { - "header": { - "artifact_id": "a3", - "type": "report" - }, - "program": "" - } - }, - { - "input": "]]>openui:artifact {\"artifact_id\":\"\",\"type\":\"report\"}\nx", - "expected": null - }, - { - "input": "]]>openui:artifact {\"type\":\"report\"}\nx", - "expected": null - }, - { - "input": "]]>openui:artifact {\"artifact_id\":\"a4\",\"type\":\"video\"}\nx", - "expected": null - }, - { - "input": "]]>openui:artifact {\"artifact_id\":\"a5\",\"type\":\"report\",\"version\":7}\nx", - "expected": { - "header": { - "artifact_id": "a5", - "type": "report" - }, - "program": "x" - } - }, - { - "input": "]]>openui:artifact not json\nx", - "expected": null - }, - { - "input": "]]>openui:artifact []\nx", - "expected": null - }, - { - "input": "]]>openui:artifact{\"artifact_id\":\"a6\",\"type\":\"report\"}\nx", - "expected": null - }, - { - "input": "]]>openui:content\nroot = X()", - "expected": null - } - ], - "wrap": { - "content": "]]>openui:content\nroot = X()", - "contentWithHeader": "]]>openui:content?thesys=true\nroot = X()", - "contentWithoutHeader": "]]>openui:content\nroot = X()", - "context": "\n]]>openui:context\n[{\"a\":1}]" - } +"separate": [{"name":"empty","input":"","expected":{"content":"","contextString":null}},{"name":"plain text","input":"Just some text","expected":{"content":"Just some text","contextString":null}},{"name":"content only","input":"]]>openui:content\nroot = Card([])","expected":{"content":"root = Card([])","contextString":null,"contentHeader":"]]>openui:content"}},{"name":"content with header attrs","input":"]]>openui:content?thesys=true&libraryVersion=0.1.0\nroot = Card([])","expected":{"content":"root = Card([])","contextString":null,"contentHeader":"]]>openui:content?thesys=true&libraryVersion=0.1.0"}},{"name":"content and context","input":"]]>openui:content\nroot = Card([])\n]]>openui:context\n[{\"f\":1}]","expected":{"content":"root = Card([])","contextString":"[{\"f\":1}]","contentHeader":"]]>openui:content"}},{"name":"context only","input":"Hello\n]]>openui:context\n[\"User clicked: Go\"]","expected":{"content":"Hello","contextString":"[\"User clicked: Go\"]"}},{"name":"context then content","input":"]]>openui:context\n[1]\n]]>openui:content\nroot = X()","expected":{"content":"root = X()","contextString":null,"contentHeader":"]]>openui:content"}},{"name":"last content wins","input":"]]>openui:content\nold\n]]>openui:content\nnew","expected":{"content":"new","contextString":null,"contentHeader":"]]>openui:content"}},{"name":"crlf separators","input":"]]>openui:content\r\nroot = X()\r\n]]>openui:context\r\n[1]","expected":{"content":"root = X()","contextString":"[1]","contentHeader":"]]>openui:content\r"}},{"name":"end marker","input":"]]>openui:content\nroot = X()\n]]>openui:end","expected":{"content":"root = X()","contextString":null,"contentHeader":"]]>openui:content","end":true}},{"name":"end marker with attrs","input":"]]>openui:content\nroot = X()\n]]>openui:end?status=done","expected":{"content":"root = X()","contextString":null,"contentHeader":"]]>openui:content","end":true}},{"name":"text after end marker","input":"]]>openui:content\nroot = X()\n]]>openui:end\ntrailing","expected":{"content":"root = X()\ntrailing","contextString":null,"contentHeader":"]]>openui:content","end":true}},{"name":"end between sections","input":"]]>openui:content\na\n]]>openui:end\n]]>openui:context\n[1]","expected":{"content":"a","contextString":"[1]","contentHeader":"]]>openui:content","end":true}},{"name":"two end markers","input":"]]>openui:content\na\n]]>openui:end\n]]>openui:end","expected":{"content":"a","contextString":null,"contentHeader":"]]>openui:content","end":true}},{"name":"crlf before end","input":"]]>openui:content\na\r\n]]>openui:end","expected":{"content":"a","contextString":null,"contentHeader":"]]>openui:content","end":true}},{"name":"partial tail one char","input":"]]>openui:content\nroot = X()\n]","expected":{"content":"root = X()","contextString":null,"contentHeader":"]]>openui:content"}},{"name":"partial tail sentinel","input":"]]>openui:content\nroot = X()\n]]>openui:","expected":{"content":"root = X()","contextString":null,"contentHeader":"]]>openui:content"}},{"name":"partial context marker","input":"]]>openui:content\nroot = X()\n]]>openui:cont","expected":{"content":"root = X()","contextString":null,"contentHeader":"]]>openui:content"}},{"name":"partial end marker","input":"]]>openui:content\nroot = X()\n]]>openui:e","expected":{"content":"root = X()","contextString":null,"contentHeader":"]]>openui:content"}},{"name":"bracket that isn't a marker","input":"]]>openui:content\nx = [1, 2]","expected":{"content":"x = [1, 2","contextString":null,"contentHeader":"]]>openui:content"}},{"name":"marker header without newline","input":"]]>openui:content","expected":{"content":"","contextString":null,"contentHeader":"]]>openui:content"}},{"name":"markers on one line","input":"]]>openui:content]]>openui:context\n[1]","expected":{"content":"","contextString":"[1]","contentHeader":"]]>openui:content]]>openui:context"}},{"name":"emoji","input":"]]>openui:content\nroot = TextContent(\"🙂 hi\")\n]]>openui:context\n[\"🎉\"]","expected":{"content":"root = TextContent(\"🙂 hi\")","contextString":"[\"🎉\"]","contentHeader":"]]>openui:content"}},{"name":"legacy xml","input":"root = X()\n[{\"a\":1}]","expected":{"content":"root = X()","contextString":"[{\"a\":1}]"}},{"name":"legacy content only","input":"root = X() ","expected":{"content":"root = X()","contextString":null}},{"name":"legacy context only","input":"text\n[\"x\"]\n","expected":{"content":"text","contextString":"[\"x\"]"}},{"name":"legacy unclosed","input":"root = X()","expected":{"content":"root = X()","contextString":null}},{"name":"legacy text after context","input":"[1] more","expected":{"content":"[1] more","contextString":null}}], +"langSyntax": [{"input":"```openui-lang\nroot = X()\n```","expected":true},{"input":"root = X()","expected":true},{"input":"root=X()","expected":true},{"input":" root = X()","expected":true},{"input":"intro\n\troot = X()","expected":true},{"input":"intro\n\n root\n= X()","expected":true},{"input":"rooted = 1","expected":false},{"input":"x root = 1","expected":false},{"input":"Just text","expected":false},{"input":"","expected":false}], +"artifacts": [{"input":"]]>openui:artifact {\"artifact_id\":\"a1\",\"type\":\"slides\",\"name\":\"Deck\",\"version\":\"2\"}\nroot = X()","expected":{"header":{"artifact_id":"a1","type":"slides","name":"Deck","version":"2"},"program":"root = X()"}},{"input":"]]>openui:artifact {\"artifact_id\":\"a2\",\"type\":\"presentation\"}\nprogram","expected":{"header":{"artifact_id":"a2","type":"slides"},"program":"program"}},{"input":"]]>openui:artifact {\"artifact_id\":\"a3\",\"type\":\"report\",\"name\":\"\"}","expected":{"header":{"artifact_id":"a3","type":"report"},"program":""}},{"input":"]]>openui:artifact {\"artifact_id\":\"\",\"type\":\"report\"}\nx","expected":null},{"input":"]]>openui:artifact {\"type\":\"report\"}\nx","expected":null},{"input":"]]>openui:artifact {\"artifact_id\":\"a4\",\"type\":\"video\"}\nx","expected":null},{"input":"]]>openui:artifact {\"artifact_id\":\"a5\",\"type\":\"report\",\"version\":7}\nx","expected":{"header":{"artifact_id":"a5","type":"report"},"program":"x"}},{"input":"]]>openui:artifact not json\nx","expected":null},{"input":"]]>openui:artifact []\nx","expected":null},{"input":"]]>openui:artifact{\"artifact_id\":\"a6\",\"type\":\"report\"}\nx","expected":null},{"input":"]]>openui:content\nroot = X()","expected":null}], +"wrap": {"content":"]]>openui:content\nroot = X()","contentWithHeader":"]]>openui:content?thesys=true\nroot = X()","contentWithoutHeader":"]]>openui:content\nroot = X()","context":"\n]]>openui:context\n[{\"a\":1}]"} } diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/openui-spec.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/openui-spec.json index ce2254ee70..d9b3e5e96c 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/openui-spec.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/openui-spec.json @@ -1,4752 +1,6 @@ { - "root": "Stack", - "components": { - "Card": { - "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)", - "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." - }, - "CardHeader": { - "signature": "CardHeader(title?: string, subtitle?: string)", - "description": "Header with optional title and subtitle" - }, - "TextContent": { - "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "MarkDownRenderer": { - "signature": "MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")", - "description": "Renders markdown text with optional container variant" - }, - "Callout": { - "signature": "Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)", - "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." - }, - "TextCallout": { - "signature": "TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)", - "description": "Text callout with variant, title, and description" - }, - "Image": { - "signature": "Image(alt: string, src?: string)", - "description": "Image with alt text and optional URL" - }, - "ImageBlock": { - "signature": "ImageBlock(src: string, alt?: string)", - "description": "Image block with loading state" - }, - "ImageGallery": { - "signature": "ImageGallery(images: {src: string, alt?: string, details?: string}[])", - "description": "Gallery grid of images with modal preview" - }, - "CodeBlock": { - "signature": "CodeBlock(language: string, codeString: string)", - "description": "Syntax-highlighted code block" - }, - "InlineHeader": { - "signature": "InlineHeader(heading: string, description?: string)", - "description": "Compact section heading with an optional one-line description, for use inside cards." - }, - "Table": { - "signature": "Table(columns: Col[])", - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", - "description": "Column definition — holds label + data array" - }, - "EditableTable": { - "signature": "EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])", - "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" - }, - "BarChart": { - "signature": "BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Vertical bars; use for comparing values across categories with one or more series" - }, - "LineChart": { - "signature": "LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Lines over categories; use for trends and continuous data over time" - }, - "AreaChart": { - "signature": "AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Filled area under lines; use for cumulative totals or volume trends over time" - }, - "RadarChart": { - "signature": "RadarChart(labels: string[], series: Series[])", - "description": "Spider/web chart; use for comparing multiple variables across one or more entities" - }, - "HorizontalBarChart": { - "signature": "HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)", - "description": "Horizontal bars; prefer when category labels are long or for ranked lists" - }, - "Series": { - "signature": "Series(category: string, values: number[])", - "description": "One data series" - }, - "PieChart": { - "signature": "PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")", - "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" - }, - "RadialChart": { - "signature": "RadialChart(labels: string[], values: number[])", - "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" - }, - "SingleStackedBarChart": { - "signature": "SingleStackedBarChart(labels: string[], values: number[])", - "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" - }, - "Slice": { - "signature": "Slice(category: string, value: number)", - "description": "One slice with label and numeric value" - }, - "ScatterChart": { - "signature": "ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)", - "description": "X/Y scatter plot; use for correlations, distributions, and clustering" - }, - "ScatterSeries": { - "signature": "ScatterSeries(name: string, points: Point[])", - "description": "Named dataset" - }, - "Point": { - "signature": "Point(x: number, y: number, z?: number)", - "description": "Data point with numeric coordinates" - }, - "Form": { - "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", - "description": "Form container with fields and explicit action buttons" - }, - "FormControl": { - "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", - "description": "Field with label, input component, and optional hint text" - }, - "Label": { - "signature": "Label(text: string)", - "description": "Text label" - }, - "Input": { - "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "TextArea": { - "signature": "TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Select": { - "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", - "description": "" - }, - "SelectItem": { - "signature": "SelectItem(value: string, label: string)", - "description": "Option for Select" - }, - "DatePicker": { - "signature": "DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Slider": { - "signature": "Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "Numeric slider input; supports continuous and discrete (stepped) variants" - }, - "CheckBoxGroup": { - "signature": "CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)", - "description": "" - }, - "CheckBoxItem": { - "signature": "CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)", - "description": "" - }, - "RadioGroup": { - "signature": "RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "RadioItem": { - "signature": "RadioItem(label: string, description: string, value: string)", - "description": "" - }, - "SwitchGroup": { - "signature": "SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)", - "description": "Group of switch toggles" - }, - "SwitchItem": { - "signature": "SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)", - "description": "Individual switch toggle" - }, - "ChipItem": { - "signature": "ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)", - "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." - }, - "Chips": { - "signature": "Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", - "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." - }, - "OptionCard": { - "signature": "OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)", - "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." - }, - "OptionCards": { - "signature": "OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", - "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." - }, - "Button": { - "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", - "description": "Clickable button" - }, - "Buttons": { - "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "IconButton": { - "signature": "IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")", - "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." - }, - "Stack": { - "signature": "Stack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)", - "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." - }, - "Tabs": { - "signature": "Tabs(items: TabItem[])", - "description": "Tabbed container" - }, - "TabItem": { - "signature": "TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])", - "description": "value is unique id, trigger is tab label, content is array of components" - }, - "Accordion": { - "signature": "Accordion(items: AccordionItem[])", - "description": "Collapsible sections" - }, - "AccordionItem": { - "signature": "AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])", - "description": "value is unique id, trigger is section title" - }, - "Steps": { - "signature": "Steps(items: StepsItem[])", - "description": "Step-by-step guide" - }, - "StepsItem": { - "signature": "StepsItem(title: string, details: string)", - "description": "title and details text for one step" - }, - "Carousel": { - "signature": "Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\")", - "description": "Horizontal scrollable carousel" - }, - "Separator": { - "signature": "Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)", - "description": "Visual divider between content sections" - }, - "TagBlock": { - "signature": "TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")", - "description": "tags is an array of strings; optional size sm | md | lg" - }, - "Tag": { - "signature": "Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")", - "description": "Styled tag/badge with optional Icon and variant" - }, - "Icon": { - "signature": "Icon(name: string, category?: string)", - "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." - }, - "EntityList": { - "signature": "EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})", - "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." - }, - "ListBlock": { - "signature": "ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")", - "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." - }, - "ListItem": { - "signature": "ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)", - "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." - }, - "Text": { - "signature": "Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", - "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "BoldText": { - "signature": "BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", - "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "IconText": { - "signature": "IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")", - "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." - }, - "ImageText": { - "signature": "ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)", - "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." - }, - "ImageTextLarge": { - "signature": "ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)", - "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." - }, - "MetricIndicatorInline": { - "signature": "MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})", - "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." - }, - "MetricIndicatorWithStrikethrough": { - "signature": "MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})", - "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." - }, - "SnippetCardItem": { - "signature": "SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)", - "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." - }, - "SnippetCardBlock": { - "signature": "SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." - }, - "OverviewCardItem": { - "signature": "OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)", - "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." - }, - "OverviewCardBlock": { - "signature": "OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." - }, - "ContextCardItem": { - "signature": "ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)", - "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." - }, - "ContextCardBlock": { - "signature": "ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." - }, - "CompositeCardItem": { - "signature": "CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})", - "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." - }, - "CompositeCardBlock": { - "signature": "CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." - }, - "VisualCardItem": { - "signature": "VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)", - "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." - }, - "VisualCardBlock": { - "signature": "VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." - }, - "Modal": { - "signature": "Modal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\")", - "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." - } - }, - "componentGroups": [ - { - "name": "Layout", - "components": [ - "Stack", - "Tabs", - "TabItem", - "Accordion", - "AccordionItem", - "Steps", - "StepsItem", - "Carousel", - "Separator", - "Modal" - ], - "notes": [ - "- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.", - "- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.", - "- Use nested Stacks when you need explicit rows/sections.", - "- Show/hide sections: $editId != \"\" ? Card([editForm]) : null", - "- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.", - "- Use Tabs for alternative views (chart types, data sections) — no $variable needed", - "- Shared filter across Tabs: same $days binding in Query args works across all TabItems" - ] - }, - { - "name": "Content", - "components": [ - "Card", - "CardHeader", - "TextContent", - "MarkDownRenderer", - "Callout", - "TextCallout", - "Image", - "ImageBlock", - "ImageGallery", - "CodeBlock", - "InlineHeader" - ], - "notes": [ - "- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).", - "- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.", - "- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null", - "- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])" - ] - }, - { - "name": "Tables", - "components": [ - "Table", - "Col", - "EditableTable" - ], - "notes": [ - "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", - "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.", - "- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName", - "- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))", - "- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))", - "- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data", - "- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input", - "- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts", - "- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")" - ] - }, - { - "name": "Charts (2D)", - "components": [ - "BarChart", - "LineChart", - "AreaChart", - "RadarChart", - "HorizontalBarChart", - "Series" - ], - "notes": [ - "- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])", - "- Use Cards to wrap charts with CardHeader for titled sections", - "- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data", - "- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])" - ] - }, - { - "name": "Charts (1D)", - "components": [ - "PieChart", - "RadialChart", - "SingleStackedBarChart", - "Slice" - ], - "notes": [ - "- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:", - "- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`", - "- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`" - ] - }, - { - "name": "Charts (Scatter)", - "components": [ - "ScatterChart", - "ScatterSeries", - "Point" - ] - }, - { - "name": "Forms", - "components": [ - "Form", - "FormControl", - "Label", - "Input", - "TextArea", - "Select", - "SelectItem", - "DatePicker", - "Slider", - "CheckBoxGroup", - "CheckBoxItem", - "RadioGroup", - "RadioItem", - "SwitchGroup", - "SwitchItem", - "Chips", - "ChipItem", - "OptionCards", - "OptionCard" - ], - "notes": [ - "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", - "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", - "- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.", - "- NEVER nest Form inside Form — each Form should be a standalone container.", - "- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.", - "- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}", - "- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric", - "- The renderer shows error messages automatically — do NOT generate error text in the UI", - "- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField", - "- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal." - ] - }, - { - "name": "Buttons", - "components": [ - "Button", - "Buttons", - "IconButton" - ], - "notes": [ - "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.", - "- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))" - ] - }, - { - "name": "Data Display", - "components": [ - "TagBlock", - "Tag", - "Icon", - "EntityList", - "ListBlock", - "ListItem" - ], - "notes": [ - "- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")", - "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.", - "- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional." - ] - }, - { - "name": "Cards", - "components": [ - "SnippetCardBlock", - "SnippetCardItem", - "OverviewCardBlock", - "OverviewCardItem", - "ContextCardBlock", - "ContextCardItem", - "CompositeCardBlock", - "CompositeCardItem", - "VisualCardBlock", - "VisualCardItem", - "Text", - "BoldText", - "IconText", - "ImageText", - "ImageTextLarge", - "MetricIndicatorInline", - "MetricIndicatorWithStrikethrough" - ], - "notes": [ - "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", - "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", - "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", - "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", - "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", - "- VisualCardItem: image-first card with a BoldText body and optional Tag.", - "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card." - ] - } - ], - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "Card": { - "$ref": "#/$defs/Card" - }, - "CardHeader": { - "$ref": "#/$defs/CardHeader" - }, - "TextContent": { - "$ref": "#/$defs/TextContent" - }, - "MarkDownRenderer": { - "$ref": "#/$defs/MarkDownRenderer" - }, - "Callout": { - "$ref": "#/$defs/Callout" - }, - "TextCallout": { - "$ref": "#/$defs/TextCallout" - }, - "Image": { - "$ref": "#/$defs/Image" - }, - "ImageBlock": { - "$ref": "#/$defs/ImageBlock" - }, - "ImageGallery": { - "$ref": "#/$defs/ImageGallery" - }, - "CodeBlock": { - "$ref": "#/$defs/CodeBlock" - }, - "InlineHeader": { - "$ref": "#/$defs/InlineHeader" - }, - "Table": { - "$ref": "#/$defs/Table" - }, - "Col": { - "$ref": "#/$defs/Col" - }, - "EditableTable": { - "$ref": "#/$defs/EditableTable" - }, - "BarChart": { - "$ref": "#/$defs/BarChart" - }, - "LineChart": { - "$ref": "#/$defs/LineChart" - }, - "AreaChart": { - "$ref": "#/$defs/AreaChart" - }, - "RadarChart": { - "$ref": "#/$defs/RadarChart" - }, - "HorizontalBarChart": { - "$ref": "#/$defs/HorizontalBarChart" - }, - "Series": { - "$ref": "#/$defs/Series" - }, - "PieChart": { - "$ref": "#/$defs/PieChart" - }, - "RadialChart": { - "$ref": "#/$defs/RadialChart" - }, - "SingleStackedBarChart": { - "$ref": "#/$defs/SingleStackedBarChart" - }, - "Slice": { - "$ref": "#/$defs/Slice" - }, - "ScatterChart": { - "$ref": "#/$defs/ScatterChart" - }, - "ScatterSeries": { - "$ref": "#/$defs/ScatterSeries" - }, - "Point": { - "$ref": "#/$defs/Point" - }, - "Form": { - "$ref": "#/$defs/Form" - }, - "FormControl": { - "$ref": "#/$defs/FormControl" - }, - "Label": { - "$ref": "#/$defs/Label" - }, - "Input": { - "$ref": "#/$defs/Input" - }, - "TextArea": { - "$ref": "#/$defs/TextArea" - }, - "Select": { - "$ref": "#/$defs/Select" - }, - "SelectItem": { - "$ref": "#/$defs/SelectItem" - }, - "DatePicker": { - "$ref": "#/$defs/DatePicker" - }, - "Slider": { - "$ref": "#/$defs/Slider" - }, - "CheckBoxGroup": { - "$ref": "#/$defs/CheckBoxGroup" - }, - "CheckBoxItem": { - "$ref": "#/$defs/CheckBoxItem" - }, - "RadioGroup": { - "$ref": "#/$defs/RadioGroup" - }, - "RadioItem": { - "$ref": "#/$defs/RadioItem" - }, - "SwitchGroup": { - "$ref": "#/$defs/SwitchGroup" - }, - "SwitchItem": { - "$ref": "#/$defs/SwitchItem" - }, - "ChipItem": { - "$ref": "#/$defs/ChipItem" - }, - "Chips": { - "$ref": "#/$defs/Chips" - }, - "OptionCard": { - "$ref": "#/$defs/OptionCard" - }, - "OptionCards": { - "$ref": "#/$defs/OptionCards" - }, - "Button": { - "$ref": "#/$defs/Button" - }, - "Buttons": { - "$ref": "#/$defs/Buttons" - }, - "IconButton": { - "$ref": "#/$defs/IconButton" - }, - "Stack": { - "$ref": "#/$defs/Stack" - }, - "Tabs": { - "$ref": "#/$defs/Tabs" - }, - "TabItem": { - "$ref": "#/$defs/TabItem" - }, - "Accordion": { - "$ref": "#/$defs/Accordion" - }, - "AccordionItem": { - "$ref": "#/$defs/AccordionItem" - }, - "Steps": { - "$ref": "#/$defs/Steps" - }, - "StepsItem": { - "$ref": "#/$defs/StepsItem" - }, - "Carousel": { - "$ref": "#/$defs/Carousel" - }, - "Separator": { - "$ref": "#/$defs/Separator" - }, - "TagBlock": { - "$ref": "#/$defs/TagBlock" - }, - "Tag": { - "$ref": "#/$defs/Tag" - }, - "Icon": { - "$ref": "#/$defs/Icon" - }, - "EntityList": { - "$ref": "#/$defs/EntityList" - }, - "ListBlock": { - "$ref": "#/$defs/ListBlock" - }, - "ListItem": { - "$ref": "#/$defs/ListItem" - }, - "Text": { - "$ref": "#/$defs/Text" - }, - "BoldText": { - "$ref": "#/$defs/BoldText" - }, - "IconText": { - "$ref": "#/$defs/IconText" - }, - "ImageText": { - "$ref": "#/$defs/ImageText" - }, - "ImageTextLarge": { - "$ref": "#/$defs/ImageTextLarge" - }, - "MetricIndicatorInline": { - "$ref": "#/$defs/MetricIndicatorInline" - }, - "MetricIndicatorWithStrikethrough": { - "$ref": "#/$defs/MetricIndicatorWithStrikethrough" - }, - "SnippetCardItem": { - "$ref": "#/$defs/SnippetCardItem" - }, - "SnippetCardBlock": { - "$ref": "#/$defs/SnippetCardBlock" - }, - "OverviewCardItem": { - "$ref": "#/$defs/OverviewCardItem" - }, - "OverviewCardBlock": { - "$ref": "#/$defs/OverviewCardBlock" - }, - "ContextCardItem": { - "$ref": "#/$defs/ContextCardItem" - }, - "ContextCardBlock": { - "$ref": "#/$defs/ContextCardBlock" - }, - "CompositeCardItem": { - "$ref": "#/$defs/CompositeCardItem" - }, - "CompositeCardBlock": { - "$ref": "#/$defs/CompositeCardBlock" - }, - "VisualCardItem": { - "$ref": "#/$defs/VisualCardItem" - }, - "VisualCardBlock": { - "$ref": "#/$defs/VisualCardBlock" - }, - "Modal": { - "$ref": "#/$defs/Modal" - } - }, - "required": [ - "Card", - "CardHeader", - "TextContent", - "MarkDownRenderer", - "Callout", - "TextCallout", - "Image", - "ImageBlock", - "ImageGallery", - "CodeBlock", - "InlineHeader", - "Table", - "Col", - "EditableTable", - "BarChart", - "LineChart", - "AreaChart", - "RadarChart", - "HorizontalBarChart", - "Series", - "PieChart", - "RadialChart", - "SingleStackedBarChart", - "Slice", - "ScatterChart", - "ScatterSeries", - "Point", - "Form", - "FormControl", - "Label", - "Input", - "TextArea", - "Select", - "SelectItem", - "DatePicker", - "Slider", - "CheckBoxGroup", - "CheckBoxItem", - "RadioGroup", - "RadioItem", - "SwitchGroup", - "SwitchItem", - "ChipItem", - "Chips", - "OptionCard", - "OptionCards", - "Button", - "Buttons", - "IconButton", - "Stack", - "Tabs", - "TabItem", - "Accordion", - "AccordionItem", - "Steps", - "StepsItem", - "Carousel", - "Separator", - "TagBlock", - "Tag", - "Icon", - "EntityList", - "ListBlock", - "ListItem", - "Text", - "BoldText", - "IconText", - "ImageText", - "ImageTextLarge", - "MetricIndicatorInline", - "MetricIndicatorWithStrikethrough", - "SnippetCardItem", - "SnippetCardBlock", - "OverviewCardItem", - "OverviewCardBlock", - "ContextCardItem", - "ContextCardBlock", - "CompositeCardItem", - "CompositeCardBlock", - "VisualCardItem", - "VisualCardBlock", - "Modal" - ], - "additionalProperties": false, - "$defs": { - "Card": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - }, - { - "$ref": "#/$defs/Tabs" - }, - { - "$ref": "#/$defs/Carousel" - }, - { - "$ref": "#/$defs/Stack" - } - ] - } - }, - "variant": { - "type": "string", - "enum": [ - "card", - "sunk", - "clear" - ] - }, - "direction": { - "type": "string", - "enum": [ - "row", - "column" - ] - }, - "gap": { - "type": "string", - "enum": [ - "none", - "xs", - "s", - "m", - "l", - "xl", - "2xl" - ] - }, - "align": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "stretch", - "baseline" - ] - }, - "justify": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "between", - "around", - "evenly" - ] - }, - "wrap": { - "type": "boolean" - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." - }, - "TextContent": { - "type": "object", - "properties": { - "text": { - "type": "string" - }, - "size": { - "type": "string", - "enum": [ - "small", - "default", - "large", - "small-heavy", - "large-heavy" - ] - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "MarkDownRenderer": { - "type": "object", - "properties": { - "textMarkdown": { - "type": "string" - }, - "variant": { - "type": "string", - "enum": [ - "clear", - "card", - "sunk" - ] - } - }, - "required": [ - "textMarkdown" - ], - "additionalProperties": false, - "description": "Renders markdown text with optional container variant" - }, - "CardHeader": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - } - }, - "additionalProperties": false, - "description": "Header with optional title and subtitle" - }, - "Callout": { - "type": "object", - "properties": { - "variant": { - "type": "string", - "enum": [ - "info", - "warning", - "error", - "success", - "neutral" - ] - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "visible": { - "type": "boolean" - } - }, - "required": [ - "variant", - "title", - "description" - ], - "additionalProperties": false, - "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." - }, - "TextCallout": { - "type": "object", - "properties": { - "variant": { - "type": "string", - "enum": [ - "neutral", - "info", - "warning", - "success", - "danger" - ] - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - } - }, - "additionalProperties": false, - "description": "Text callout with variant, title, and description" - }, - "CodeBlock": { - "type": "object", - "properties": { - "language": { - "type": "string" - }, - "codeString": { - "type": "string" - } - }, - "required": [ - "language", - "codeString" - ], - "additionalProperties": false, - "description": "Syntax-highlighted code block" - }, - "Image": { - "type": "object", - "properties": { - "alt": { - "type": "string" - }, - "src": { - "type": "string" - } - }, - "required": [ - "alt" - ], - "additionalProperties": false, - "description": "Image with alt text and optional URL" - }, - "ImageBlock": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - } - }, - "required": [ - "src" - ], - "additionalProperties": false, - "description": "Image block with loading state" - }, - "ImageGallery": { - "type": "object", - "properties": { - "images": { - "type": "array", - "items": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "details": { - "type": "string" - } - }, - "required": [ - "src" - ], - "additionalProperties": false - } - } - }, - "required": [ - "images" - ], - "additionalProperties": false, - "description": "Gallery grid of images with modal preview" - }, - "Separator": { - "type": "object", - "properties": { - "orientation": { - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - }, - "decorative": { - "type": "boolean" - } - }, - "additionalProperties": false, - "description": "Visual divider between content sections" - }, - "HorizontalBarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "grouped", - "stacked" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Horizontal bars; prefer when category labels are long or for ranked lists" - }, - "Series": { - "type": "object", - "properties": { - "category": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "category", - "values" - ], - "additionalProperties": false, - "description": "One data series" - }, - "RadarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Spider/web chart; use for comparing multiple variables across one or more entities" - }, - "PieChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - }, - "variant": { - "type": "string", - "enum": [ - "pie", - "donut" - ] - }, - "appearance": { - "type": "string", - "enum": [ - "circular", - "semiCircular" - ] - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" - }, - "RadialChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" - }, - "SingleStackedBarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" - }, - "ScatterChart": { - "type": "object", - "properties": { - "datasets": { - "type": "array", - "items": { - "$ref": "#/$defs/ScatterSeries" - } - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - } - }, - "required": [ - "datasets" - ], - "additionalProperties": false, - "description": "X/Y scatter plot; use for correlations, distributions, and clustering" - }, - "ScatterSeries": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "points": { - "type": "array", - "items": { - "$ref": "#/$defs/Point" - } - } - }, - "required": [ - "name", - "points" - ], - "additionalProperties": false, - "description": "Named dataset" - }, - "Point": { - "type": "object", - "properties": { - "x": { - "type": "number" - }, - "y": { - "type": "number" - }, - "z": { - "type": "number" - } - }, - "required": [ - "x", - "y" - ], - "additionalProperties": false, - "description": "Data point with numeric coordinates" - }, - "AreaChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "linear", - "natural", - "step" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Filled area under lines; use for cumulative totals or volume trends over time" - }, - "BarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "grouped", - "stacked" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Vertical bars; use for comparing values across categories with one or more series" - }, - "LineChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "linear", - "natural", - "step" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Lines over categories; use for trends and continuous data over time" - }, - "Table": { - "type": "object", - "properties": { - "columns": { - "type": "array", - "items": { - "$ref": "#/$defs/Col" - } - } - }, - "required": [ - "columns" - ], - "additionalProperties": false, - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "data": {}, - "type": { - "type": "string", - "enum": [ - "string", - "number", - "action" - ] - } - }, - "required": [ - "label", - "data" - ], - "additionalProperties": false, - "description": "Column definition — holds label + data array" - }, - "TagBlock": { - "type": "object", - "properties": { - "tags": { - "type": "array", - "items": { - "type": "string" - } - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "tags" - ], - "additionalProperties": false, - "description": "tags is an array of strings; optional size sm | md | lg" - }, - "Form": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "buttons": { - "$ref": "#/$defs/Buttons" - }, - "fields": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/FormControl" - } - } - }, - "required": [ - "name", - "buttons", - "fields" - ], - "additionalProperties": false, - "description": "Form container with fields and explicit action buttons" - }, - "Buttons": { - "type": "object", - "properties": { - "buttons": { - "type": "array", - "items": { - "$ref": "#/$defs/Button" - } - }, - "direction": { - "type": "string", - "enum": [ - "row", - "column" - ] - } - }, - "required": [ - "buttons" - ], - "additionalProperties": false, - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "Button": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "variant": { - "type": "string", - "enum": [ - "primary", - "secondary", - "tertiary" - ] - }, - "type": { - "type": "string", - "enum": [ - "normal", - "destructive" - ] - }, - "size": { - "type": "string", - "enum": [ - "extra-small", - "small", - "medium", - "large" - ] - } - }, - "required": [ - "label" - ], - "additionalProperties": false, - "description": "Clickable button" - }, - "FormControl": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "input": { - "anyOf": [ - { - "$ref": "#/$defs/Input" - }, - { - "$ref": "#/$defs/TextArea" - }, - { - "$ref": "#/$defs/Select" - }, - { - "$ref": "#/$defs/DatePicker" - }, - { - "$ref": "#/$defs/Slider" - }, - { - "$ref": "#/$defs/CheckBoxGroup" - }, - { - "$ref": "#/$defs/RadioGroup" - }, - { - "$ref": "#/$defs/Chips" - }, - { - "$ref": "#/$defs/OptionCards" - } - ] - }, - "hint": { - "type": "string" - } - }, - "required": [ - "label", - "input" - ], - "additionalProperties": false, - "description": "Field with label, input component, and optional hint text" - }, - "Input": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "placeholder": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "text", - "email", - "password", - "number", - "url" - ] - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "TextArea": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "placeholder": { - "type": "string" - }, - "rows": { - "type": "number" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "Select": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/SelectItem" - } - }, - "placeholder": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - }, - "size": { - "type": "string", - "enum": [ - "small", - "medium", - "large" - ] - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "SelectItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false, - "description": "Option for Select" - }, - "DatePicker": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "mode": { - "type": "string", - "enum": [ - "single", - "range" - ] - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": {} - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "Slider": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "variant": { - "type": "string", - "enum": [ - "continuous", - "discrete" - ] - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "step": { - "type": "number" - }, - "defaultValue": { - "type": "array", - "items": { - "type": "number" - } - }, - "label": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "name", - "variant", - "min", - "max" - ], - "additionalProperties": false, - "description": "Numeric slider input; supports continuous and discrete (stepped) variants" - }, - "CheckBoxGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/CheckBoxItem" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": { - "type": "boolean" - } - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "CheckBoxItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "defaultChecked": { - "type": "boolean" - } - }, - "required": [ - "label", - "description", - "name" - ], - "additionalProperties": false - }, - "RadioGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/RadioItem" - } - }, - "defaultValue": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "RadioItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "value": { - "type": "string" - } - }, - "required": [ - "label", - "description", - "value" - ], - "additionalProperties": false - }, - "Chips": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "type": { - "default": "multiple", - "type": "string", - "enum": [ - "single", - "multiple" - ] - }, - "items": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/ChipItem" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "defaultValue": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - } - }, - "required": [ - "name", - "type", - "items" - ], - "additionalProperties": false, - "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." - }, - "ChipItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "disabled": { - "type": "boolean" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false, - "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." - }, - "Icon": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "category": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false, - "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." - }, - "OptionCards": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "type": { - "default": "single", - "type": "string", - "enum": [ - "single", - "multiple" - ] - }, - "items": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/OptionCard" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "defaultValue": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - } - }, - "required": [ - "name", - "type", - "items" - ], - "additionalProperties": false, - "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." - }, - "OptionCard": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "topContent": { - "anyOf": [ - { - "$ref": "#/$defs/Icon" - }, - { - "$ref": "#/$defs/Image" - } - ] - }, - "disabled": { - "type": "boolean" - } - }, - "required": [ - "value", - "title" - ], - "additionalProperties": false, - "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." - }, - "IconButton": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "variant": { - "type": "string", - "enum": [ - "primary", - "secondary", - "tertiary" - ] - }, - "size": { - "type": "string", - "enum": [ - "extra-small", - "small", - "medium", - "large" - ] - }, - "shape": { - "type": "string", - "enum": [ - "square", - "circle" - ] - } - }, - "required": [ - "name", - "icon" - ], - "additionalProperties": false, - "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." - }, - "Steps": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/StepsItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Step-by-step guide" - }, - "StepsItem": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "details": { - "type": "string" - } - }, - "required": [ - "title", - "details" - ], - "additionalProperties": false, - "description": "title and details text for one step" - }, - "InlineHeader": { - "type": "object", - "properties": { - "heading": { - "type": "string" - }, - "description": { - "type": "string" - } - }, - "required": [ - "heading" - ], - "additionalProperties": false, - "description": "Compact section heading with an optional one-line description, for use inside cards." - }, - "EntityList": { - "type": "object", - "properties": { - "rows": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - } - }, - "size": { - "default": "default", - "type": "string", - "enum": [ - "small", - "default" - ] - }, - "header": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - }, - "footer": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - } - }, - "required": [ - "rows", - "size" - ], - "additionalProperties": false, - "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." - }, - "EditableTable": { - "type": "object", - "properties": { - "name": { - "default": "", - "type": "string" - }, - "columns": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "text", - "number", - "date-single", - "select", - "url" - ] - }, - "key": { - "default": "default", - "type": "string" - }, - "header": { - "default": "", - "type": "string" - }, - "width": { - "type": "number" - }, - "options": { - "type": "array", - "items": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false - } - } - }, - "required": [ - "type", - "key", - "header" - ], - "additionalProperties": false - } - }, - "data": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - } - } - }, - "required": [ - "id", - "values" - ], - "additionalProperties": false - } - } - }, - "required": [ - "name", - "columns", - "data" - ], - "additionalProperties": false, - "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" - }, - "SnippetCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/SnippetCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." - }, - "SnippetCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "lhs": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - } - ] - }, - "rhs": { - "anyOf": [ - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/BoldText" - } - ] - } - }, - "required": [ - "lhs" - ], - "additionalProperties": false, - "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." - }, - "IconText": { - "type": "object", - "properties": { - "icon": { - "$ref": "#/$defs/Icon" - }, - "iconVariant": { - "default": "neutral", - "type": "string", - "enum": [ - "neutral", - "info", - "success", - "warning", - "danger", - "inverted", - "filled", - "soft" - ] - }, - "iconSize": { - "default": "m", - "type": "string", - "enum": [ - "xs", - "s", - "m", - "l", - "xl", - "sm", - "md", - "lg" - ] - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - }, - "layout": { - "default": "horizontal", - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - } - }, - "required": [ - "icon", - "iconVariant", - "iconSize", - "title", - "bold", - "layout" - ], - "additionalProperties": false, - "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." - }, - "ImageText": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - }, - "layout": { - "default": "horizontal", - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - }, - "imageSize": { - "type": "number" - } - }, - "required": [ - "src", - "title", - "bold", - "layout" - ], - "additionalProperties": false, - "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." - }, - "Text": { - "type": "object", - "properties": { - "variant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - }, - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "subtextVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number", - "metric" - ] - }, - "size": { - "default": "sm", - "type": "string", - "enum": [ - "xs", - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "variant", - "value", - "subtextVariant", - "size" - ], - "additionalProperties": false, - "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "BoldText": { - "type": "object", - "properties": { - "variant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - }, - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "subtextVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number", - "metric" - ] - }, - "size": { - "default": "sm", - "type": "string", - "enum": [ - "xs", - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "variant", - "value", - "subtextVariant", - "size" - ], - "additionalProperties": false, - "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "OverviewCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/OverviewCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." - }, - "OverviewCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "top": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - }, - { - "$ref": "#/$defs/Text" - } - ] - }, - "bottom": { - "$ref": "#/$defs/MetricIndicatorInline" - } - }, - "required": [ - "top" - ], - "additionalProperties": false, - "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." - }, - "MetricIndicatorInline": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "trend": { - "type": "object", - "properties": { - "direction": { - "type": "string", - "enum": [ - "up", - "down" - ] - }, - "value": { - "type": "number" - } - }, - "required": [ - "direction", - "value" - ], - "additionalProperties": false - } - }, - "required": [ - "value" - ], - "additionalProperties": false, - "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." - }, - "ContextCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/ContextCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." - }, - "ContextCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "title": { - "anyOf": [ - { - "type": "string" - }, - { - "$ref": "#/$defs/Tag" - } - ] - }, - "body": { - "type": "string" - }, - "bgColor": { - "type": "string", - "enum": [ - "gray" - ] - }, - "bgImageSrc": { - "type": "string" - }, - "bgImageAlt": { - "type": "string" - } - }, - "required": [ - "title" - ], - "additionalProperties": false, - "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." - }, - "Tag": { - "type": "object", - "properties": { - "text": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - }, - "variant": { - "type": "string", - "enum": [ - "neutral", - "info", - "success", - "warning", - "danger" - ] - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Styled tag/badge with optional Icon and variant" - }, - "CompositeCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/CompositeCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." - }, - "CompositeCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "header": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - }, - { - "$ref": "#/$defs/ImageTextLarge" - }, - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/Image" - } - ] - }, - "body": { - "default": [], - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/BoldText" - }, - { - "$ref": "#/$defs/MetricIndicatorInline" - }, - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/ListBlock" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/EntityList" - } - ] - } - }, - "footer": { - "type": "object", - "properties": { - "price": { - "anyOf": [ - { - "$ref": "#/$defs/BoldText" - }, - { - "$ref": "#/$defs/MetricIndicatorWithStrikethrough" - } - ] - }, - "button": { - "$ref": "#/$defs/Button" - } - }, - "additionalProperties": false - } - }, - "required": [ - "body" - ], - "additionalProperties": false, - "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." - }, - "ImageTextLarge": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - } - }, - "required": [ - "src", - "title", - "bold" - ], - "additionalProperties": false, - "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." - }, - "ListBlock": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/ListItem" - } - }, - "variant": { - "type": "string", - "enum": [ - "number", - "image" - ] - }, - "size": { - "type": "string", - "enum": [ - "default", - "small" - ] - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." - }, - "ListItem": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "image": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - } - }, - "required": [ - "src", - "alt" - ], - "additionalProperties": false - }, - "actionLabel": { - "type": "string" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "title" - ], - "additionalProperties": false, - "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." - }, - "MetricIndicatorWithStrikethrough": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "previousValue": { - "type": "string" - }, - "trend": { - "type": "object", - "properties": { - "direction": { - "type": "string", - "enum": [ - "up", - "down" - ] - }, - "value": { - "type": "number" - } - }, - "required": [ - "direction", - "value" - ], - "additionalProperties": false - } - }, - "required": [ - "value" - ], - "additionalProperties": false, - "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." - }, - "VisualCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/VisualCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." - }, - "VisualCardItem": { - "type": "object", - "properties": { - "body": { - "$ref": "#/$defs/BoldText" - }, - "id": { - "type": "string" - }, - "bgImageSrc": { - "type": "string" - }, - "tag": { - "$ref": "#/$defs/Tag" - }, - "bgImageAlt": { - "type": "string" - } - }, - "required": [ - "body" - ], - "additionalProperties": false, - "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." - }, - "Tabs": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/TabItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Tabbed container" - }, - "TabItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "trigger": { - "type": "string" - }, - "content": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - } - }, - "required": [ - "value", - "trigger", - "content" - ], - "additionalProperties": false, - "description": "value is unique id, trigger is tab label, content is array of components" - }, - "Carousel": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - } - }, - "variant": { - "type": "string", - "enum": [ - "card", - "sunk" - ] - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Horizontal scrollable carousel" - }, - "Stack": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": {} - }, - "direction": { - "type": "string", - "enum": [ - "row", - "column" - ] - }, - "gap": { - "type": "string", - "enum": [ - "none", - "xs", - "s", - "m", - "l", - "xl", - "2xl" - ] - }, - "align": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "stretch", - "baseline" - ] - }, - "justify": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "between", - "around", - "evenly" - ] - }, - "wrap": { - "type": "boolean" - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." - }, - "Slice": { - "type": "object", - "properties": { - "category": { - "type": "string" - }, - "value": { - "type": "number" - } - }, - "required": [ - "category", - "value" - ], - "additionalProperties": false, - "description": "One slice with label and numeric value" - }, - "Label": { - "type": "object", - "properties": { - "text": { - "type": "string" - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Text label" - }, - "SwitchGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/SwitchItem" - } - }, - "variant": { - "type": "string", - "enum": [ - "clear", - "card", - "sunk" - ] - }, - "value": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": { - "type": "boolean" - } - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false, - "description": "Group of switch toggles" - }, - "SwitchItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "defaultChecked": { - "type": "boolean" - } - }, - "required": [ - "name" - ], - "additionalProperties": false, - "description": "Individual switch toggle" - }, - "Accordion": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/AccordionItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Collapsible sections" - }, - "AccordionItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "trigger": { - "type": "string" - }, - "content": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - } - }, - "required": [ - "value", - "trigger", - "content" - ], - "additionalProperties": false, - "description": "value is unique id, trigger is section title" - }, - "Modal": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "open": { - "type": "boolean" - }, - "children": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "title", - "children" - ], - "additionalProperties": false, - "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." - } - } - } +"root": "Stack", +"components": {"Card":{"signature":"Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)","description":"Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts."},"CardHeader":{"signature":"CardHeader(title?: string, subtitle?: string)","description":"Header with optional title and subtitle"},"TextContent":{"signature":"TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")","description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"MarkDownRenderer":{"signature":"MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")","description":"Renders markdown text with optional container variant"},"Callout":{"signature":"Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)","description":"Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false."},"TextCallout":{"signature":"TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)","description":"Text callout with variant, title, and description"},"Image":{"signature":"Image(alt: string, src?: string)","description":"Image with alt text and optional URL"},"ImageBlock":{"signature":"ImageBlock(src: string, alt?: string)","description":"Image block with loading state"},"ImageGallery":{"signature":"ImageGallery(images: {src: string, alt?: string, details?: string}[])","description":"Gallery grid of images with modal preview"},"CodeBlock":{"signature":"CodeBlock(language: string, codeString: string)","description":"Syntax-highlighted code block"},"InlineHeader":{"signature":"InlineHeader(heading: string, description?: string)","description":"Compact section heading with an optional one-line description, for use inside cards."},"Table":{"signature":"Table(columns: Col[])","description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"signature":"Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")","description":"Column definition — holds label + data array"},"EditableTable":{"signature":"EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])","description":"Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field"},"BarChart":{"signature":"BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)","description":"Vertical bars; use for comparing values across categories with one or more series"},"LineChart":{"signature":"LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)","description":"Lines over categories; use for trends and continuous data over time"},"AreaChart":{"signature":"AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)","description":"Filled area under lines; use for cumulative totals or volume trends over time"},"RadarChart":{"signature":"RadarChart(labels: string[], series: Series[])","description":"Spider/web chart; use for comparing multiple variables across one or more entities"},"HorizontalBarChart":{"signature":"HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)","description":"Horizontal bars; prefer when category labels are long or for ranked lists"},"Series":{"signature":"Series(category: string, values: number[])","description":"One data series"},"PieChart":{"signature":"PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")","description":"Circular slices; use plucked arrays: PieChart(data.categories, data.values)"},"RadialChart":{"signature":"RadialChart(labels: string[], values: number[])","description":"Radial bars; use plucked arrays: RadialChart(data.categories, data.values)"},"SingleStackedBarChart":{"signature":"SingleStackedBarChart(labels: string[], values: number[])","description":"Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)"},"Slice":{"signature":"Slice(category: string, value: number)","description":"One slice with label and numeric value"},"ScatterChart":{"signature":"ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)","description":"X/Y scatter plot; use for correlations, distributions, and clustering"},"ScatterSeries":{"signature":"ScatterSeries(name: string, points: Point[])","description":"Named dataset"},"Point":{"signature":"Point(x: number, y: number, z?: number)","description":"Data point with numeric coordinates"},"Form":{"signature":"Form(name: string, buttons: Buttons, fields?: FormControl[])","description":"Form container with fields and explicit action buttons"},"FormControl":{"signature":"FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)","description":"Field with label, input component, and optional hint text"},"Label":{"signature":"Label(text: string)","description":"Text label"},"Input":{"signature":"Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"TextArea":{"signature":"TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Select":{"signature":"Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")","description":""},"SelectItem":{"signature":"SelectItem(value: string, label: string)","description":"Option for Select"},"DatePicker":{"signature":"DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Slider":{"signature":"Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":"Numeric slider input; supports continuous and discrete (stepped) variants"},"CheckBoxGroup":{"signature":"CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)","description":""},"CheckBoxItem":{"signature":"CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)","description":""},"RadioGroup":{"signature":"RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"RadioItem":{"signature":"RadioItem(label: string, description: string, value: string)","description":""},"SwitchGroup":{"signature":"SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)","description":"Group of switch toggles"},"SwitchItem":{"signature":"SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)","description":"Individual switch toggle"},"ChipItem":{"signature":"ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)","description":"A single selectable chip inside a Chips group, with a value, label and optional icon."},"Chips":{"signature":"Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])","description":"A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`."},"OptionCard":{"signature":"OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)","description":"A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top."},"OptionCards":{"signature":"OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])","description":"A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`."},"Button":{"signature":"Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")","description":"Clickable button"},"Buttons":{"signature":"Buttons(buttons: Button[], direction?: \"row\" | \"column\")","description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"IconButton":{"signature":"IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")","description":"Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click."},"Stack":{"signature":"Stack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)","description":"Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"."},"Tabs":{"signature":"Tabs(items: TabItem[])","description":"Tabbed container"},"TabItem":{"signature":"TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])","description":"value is unique id, trigger is tab label, content is array of components"},"Accordion":{"signature":"Accordion(items: AccordionItem[])","description":"Collapsible sections"},"AccordionItem":{"signature":"AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])","description":"value is unique id, trigger is section title"},"Steps":{"signature":"Steps(items: StepsItem[])","description":"Step-by-step guide"},"StepsItem":{"signature":"StepsItem(title: string, details: string)","description":"title and details text for one step"},"Carousel":{"signature":"Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\")","description":"Horizontal scrollable carousel"},"Separator":{"signature":"Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)","description":"Visual divider between content sections"},"TagBlock":{"signature":"TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")","description":"tags is an array of strings; optional size sm | md | lg"},"Tag":{"signature":"Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")","description":"Styled tag/badge with optional Icon and variant"},"Icon":{"signature":"Icon(name: string, category?: string)","description":"A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve."},"EntityList":{"signature":"EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})","description":"Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers."},"ListBlock":{"signature":"ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")","description":"A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list."},"ListItem":{"signature":"ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)","description":"Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable."},"Text":{"signature":"Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")","description":"Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"BoldText":{"signature":"BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")","description":"Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"IconText":{"signature":"IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")","description":"An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color."},"ImageText":{"signature":"ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)","description":"A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL."},"ImageTextLarge":{"signature":"ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)","description":"A full-width banner image above a bold title and optional subtitle. src must be a real image URL."},"MetricIndicatorInline":{"signature":"MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})","description":"Headline metric value with an optional +/- percentage trend and subtext, all on one line."},"MetricIndicatorWithStrikethrough":{"signature":"MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})","description":"Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below."},"SnippetCardItem":{"signature":"SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)","description":"One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)."},"SnippetCardBlock":{"signature":"SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action."},"OverviewCardItem":{"signature":"OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)","description":"One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom."},"OverviewCardBlock":{"signature":"OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action."},"ContextCardItem":{"signature":"ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)","description":"A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image."},"ContextCardBlock":{"signature":"ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable."},"CompositeCardItem":{"signature":"CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})","description":"A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer."},"CompositeCardBlock":{"signature":"CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable."},"VisualCardItem":{"signature":"VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)","description":"A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)."},"VisualCardBlock":{"signature":"VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable."},"Modal":{"signature":"Modal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\")","description":"Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children."}}, +"componentGroups": [{"name":"Layout","components":["Stack","Tabs","TabItem","Accordion","AccordionItem","Steps","StepsItem","Carousel","Separator","Modal"],"notes":["- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.","- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.","- Use nested Stacks when you need explicit rows/sections.","- Show/hide sections: $editId != \"\" ? Card([editForm]) : null","- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.","- Use Tabs for alternative views (chart types, data sections) — no $variable needed","- Shared filter across Tabs: same $days binding in Query args works across all TabItems"]},{"name":"Content","components":["Card","CardHeader","TextContent","MarkDownRenderer","Callout","TextCallout","Image","ImageBlock","ImageGallery","CodeBlock","InlineHeader"],"notes":["- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).","- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.","- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null","- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])"]},{"name":"Tables","components":["Table","Col","EditableTable"],"notes":["- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).","- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.","- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName","- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))","- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))","- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data","- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input","- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts","- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")"]},{"name":"Charts (2D)","components":["BarChart","LineChart","AreaChart","RadarChart","HorizontalBarChart","Series"],"notes":["- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])","- Use Cards to wrap charts with CardHeader for titled sections","- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data","- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])"]},{"name":"Charts (1D)","components":["PieChart","RadialChart","SingleStackedBarChart","Slice"],"notes":["- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:","- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`","- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`"]},{"name":"Charts (Scatter)","components":["ScatterChart","ScatterSeries","Point"]},{"name":"Forms","components":["Form","FormControl","Label","Input","TextArea","Select","SelectItem","DatePicker","Slider","CheckBoxGroup","CheckBoxItem","RadioGroup","RadioItem","SwitchGroup","SwitchItem","Chips","ChipItem","OptionCards","OptionCard"],"notes":["- Chips: compact single/multiple selection pills. Use ChipItem references for each option.","- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.","- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.","- NEVER nest Form inside Form — each Form should be a standalone container.","- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.","- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}","- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric","- The renderer shows error messages automatically — do NOT generate error text in the UI","- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField","- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal."]},{"name":"Buttons","components":["Button","Buttons","IconButton"],"notes":["- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.","- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))"]},{"name":"Data Display","components":["TagBlock","Tag","Icon","EntityList","ListBlock","ListItem"],"notes":["- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")","- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.","- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional."]},{"name":"Cards","components":["SnippetCardBlock","SnippetCardItem","OverviewCardBlock","OverviewCardItem","ContextCardBlock","ContextCardItem","CompositeCardBlock","CompositeCardItem","VisualCardBlock","VisualCardItem","Text","BoldText","IconText","ImageText","ImageTextLarge","MetricIndicatorInline","MetricIndicatorWithStrikethrough"],"notes":["- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.","- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.","- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.","- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.","- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.","- VisualCardItem: image-first card with a BoldText body and optional Tag.","- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card."]}], +"schema": {"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"Card":{"$ref":"#/$defs/Card"},"CardHeader":{"$ref":"#/$defs/CardHeader"},"TextContent":{"$ref":"#/$defs/TextContent"},"MarkDownRenderer":{"$ref":"#/$defs/MarkDownRenderer"},"Callout":{"$ref":"#/$defs/Callout"},"TextCallout":{"$ref":"#/$defs/TextCallout"},"Image":{"$ref":"#/$defs/Image"},"ImageBlock":{"$ref":"#/$defs/ImageBlock"},"ImageGallery":{"$ref":"#/$defs/ImageGallery"},"CodeBlock":{"$ref":"#/$defs/CodeBlock"},"InlineHeader":{"$ref":"#/$defs/InlineHeader"},"Table":{"$ref":"#/$defs/Table"},"Col":{"$ref":"#/$defs/Col"},"EditableTable":{"$ref":"#/$defs/EditableTable"},"BarChart":{"$ref":"#/$defs/BarChart"},"LineChart":{"$ref":"#/$defs/LineChart"},"AreaChart":{"$ref":"#/$defs/AreaChart"},"RadarChart":{"$ref":"#/$defs/RadarChart"},"HorizontalBarChart":{"$ref":"#/$defs/HorizontalBarChart"},"Series":{"$ref":"#/$defs/Series"},"PieChart":{"$ref":"#/$defs/PieChart"},"RadialChart":{"$ref":"#/$defs/RadialChart"},"SingleStackedBarChart":{"$ref":"#/$defs/SingleStackedBarChart"},"Slice":{"$ref":"#/$defs/Slice"},"ScatterChart":{"$ref":"#/$defs/ScatterChart"},"ScatterSeries":{"$ref":"#/$defs/ScatterSeries"},"Point":{"$ref":"#/$defs/Point"},"Form":{"$ref":"#/$defs/Form"},"FormControl":{"$ref":"#/$defs/FormControl"},"Label":{"$ref":"#/$defs/Label"},"Input":{"$ref":"#/$defs/Input"},"TextArea":{"$ref":"#/$defs/TextArea"},"Select":{"$ref":"#/$defs/Select"},"SelectItem":{"$ref":"#/$defs/SelectItem"},"DatePicker":{"$ref":"#/$defs/DatePicker"},"Slider":{"$ref":"#/$defs/Slider"},"CheckBoxGroup":{"$ref":"#/$defs/CheckBoxGroup"},"CheckBoxItem":{"$ref":"#/$defs/CheckBoxItem"},"RadioGroup":{"$ref":"#/$defs/RadioGroup"},"RadioItem":{"$ref":"#/$defs/RadioItem"},"SwitchGroup":{"$ref":"#/$defs/SwitchGroup"},"SwitchItem":{"$ref":"#/$defs/SwitchItem"},"ChipItem":{"$ref":"#/$defs/ChipItem"},"Chips":{"$ref":"#/$defs/Chips"},"OptionCard":{"$ref":"#/$defs/OptionCard"},"OptionCards":{"$ref":"#/$defs/OptionCards"},"Button":{"$ref":"#/$defs/Button"},"Buttons":{"$ref":"#/$defs/Buttons"},"IconButton":{"$ref":"#/$defs/IconButton"},"Stack":{"$ref":"#/$defs/Stack"},"Tabs":{"$ref":"#/$defs/Tabs"},"TabItem":{"$ref":"#/$defs/TabItem"},"Accordion":{"$ref":"#/$defs/Accordion"},"AccordionItem":{"$ref":"#/$defs/AccordionItem"},"Steps":{"$ref":"#/$defs/Steps"},"StepsItem":{"$ref":"#/$defs/StepsItem"},"Carousel":{"$ref":"#/$defs/Carousel"},"Separator":{"$ref":"#/$defs/Separator"},"TagBlock":{"$ref":"#/$defs/TagBlock"},"Tag":{"$ref":"#/$defs/Tag"},"Icon":{"$ref":"#/$defs/Icon"},"EntityList":{"$ref":"#/$defs/EntityList"},"ListBlock":{"$ref":"#/$defs/ListBlock"},"ListItem":{"$ref":"#/$defs/ListItem"},"Text":{"$ref":"#/$defs/Text"},"BoldText":{"$ref":"#/$defs/BoldText"},"IconText":{"$ref":"#/$defs/IconText"},"ImageText":{"$ref":"#/$defs/ImageText"},"ImageTextLarge":{"$ref":"#/$defs/ImageTextLarge"},"MetricIndicatorInline":{"$ref":"#/$defs/MetricIndicatorInline"},"MetricIndicatorWithStrikethrough":{"$ref":"#/$defs/MetricIndicatorWithStrikethrough"},"SnippetCardItem":{"$ref":"#/$defs/SnippetCardItem"},"SnippetCardBlock":{"$ref":"#/$defs/SnippetCardBlock"},"OverviewCardItem":{"$ref":"#/$defs/OverviewCardItem"},"OverviewCardBlock":{"$ref":"#/$defs/OverviewCardBlock"},"ContextCardItem":{"$ref":"#/$defs/ContextCardItem"},"ContextCardBlock":{"$ref":"#/$defs/ContextCardBlock"},"CompositeCardItem":{"$ref":"#/$defs/CompositeCardItem"},"CompositeCardBlock":{"$ref":"#/$defs/CompositeCardBlock"},"VisualCardItem":{"$ref":"#/$defs/VisualCardItem"},"VisualCardBlock":{"$ref":"#/$defs/VisualCardBlock"},"Modal":{"$ref":"#/$defs/Modal"}},"required":["Card","CardHeader","TextContent","MarkDownRenderer","Callout","TextCallout","Image","ImageBlock","ImageGallery","CodeBlock","InlineHeader","Table","Col","EditableTable","BarChart","LineChart","AreaChart","RadarChart","HorizontalBarChart","Series","PieChart","RadialChart","SingleStackedBarChart","Slice","ScatterChart","ScatterSeries","Point","Form","FormControl","Label","Input","TextArea","Select","SelectItem","DatePicker","Slider","CheckBoxGroup","CheckBoxItem","RadioGroup","RadioItem","SwitchGroup","SwitchItem","ChipItem","Chips","OptionCard","OptionCards","Button","Buttons","IconButton","Stack","Tabs","TabItem","Accordion","AccordionItem","Steps","StepsItem","Carousel","Separator","TagBlock","Tag","Icon","EntityList","ListBlock","ListItem","Text","BoldText","IconText","ImageText","ImageTextLarge","MetricIndicatorInline","MetricIndicatorWithStrikethrough","SnippetCardItem","SnippetCardBlock","OverviewCardItem","OverviewCardBlock","ContextCardItem","ContextCardBlock","CompositeCardItem","CompositeCardBlock","VisualCardItem","VisualCardBlock","Modal"],"additionalProperties":false,"$defs":{"Card":{"type":"object","properties":{"children":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"},{"$ref":"#/$defs/Tabs"},{"$ref":"#/$defs/Carousel"},{"$ref":"#/$defs/Stack"}]}},"variant":{"type":"string","enum":["card","sunk","clear"]},"direction":{"type":"string","enum":["row","column"]},"gap":{"type":"string","enum":["none","xs","s","m","l","xl","2xl"]},"align":{"type":"string","enum":["start","center","end","stretch","baseline"]},"justify":{"type":"string","enum":["start","center","end","between","around","evenly"]},"wrap":{"type":"boolean"}},"required":["children"],"additionalProperties":false,"description":"Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts."},"TextContent":{"type":"object","properties":{"text":{"type":"string"},"size":{"type":"string","enum":["small","default","large","small-heavy","large-heavy"]}},"required":["text"],"additionalProperties":false,"description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"MarkDownRenderer":{"type":"object","properties":{"textMarkdown":{"type":"string"},"variant":{"type":"string","enum":["clear","card","sunk"]}},"required":["textMarkdown"],"additionalProperties":false,"description":"Renders markdown text with optional container variant"},"CardHeader":{"type":"object","properties":{"title":{"type":"string"},"subtitle":{"type":"string"}},"additionalProperties":false,"description":"Header with optional title and subtitle"},"Callout":{"type":"object","properties":{"variant":{"type":"string","enum":["info","warning","error","success","neutral"]},"title":{"type":"string"},"description":{"type":"string"},"visible":{"type":"boolean"}},"required":["variant","title","description"],"additionalProperties":false,"description":"Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false."},"TextCallout":{"type":"object","properties":{"variant":{"type":"string","enum":["neutral","info","warning","success","danger"]},"title":{"type":"string"},"description":{"type":"string"}},"additionalProperties":false,"description":"Text callout with variant, title, and description"},"CodeBlock":{"type":"object","properties":{"language":{"type":"string"},"codeString":{"type":"string"}},"required":["language","codeString"],"additionalProperties":false,"description":"Syntax-highlighted code block"},"Image":{"type":"object","properties":{"alt":{"type":"string"},"src":{"type":"string"}},"required":["alt"],"additionalProperties":false,"description":"Image with alt text and optional URL"},"ImageBlock":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"}},"required":["src"],"additionalProperties":false,"description":"Image block with loading state"},"ImageGallery":{"type":"object","properties":{"images":{"type":"array","items":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"details":{"type":"string"}},"required":["src"],"additionalProperties":false}}},"required":["images"],"additionalProperties":false,"description":"Gallery grid of images with modal preview"},"Separator":{"type":"object","properties":{"orientation":{"type":"string","enum":["horizontal","vertical"]},"decorative":{"type":"boolean"}},"additionalProperties":false,"description":"Visual divider between content sections"},"HorizontalBarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["grouped","stacked"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"}},"required":["labels","series"],"additionalProperties":false,"description":"Horizontal bars; prefer when category labels are long or for ranked lists"},"Series":{"type":"object","properties":{"category":{"type":"string"},"values":{"type":"array","items":{"type":"number"}}},"required":["category","values"],"additionalProperties":false,"description":"One data series"},"RadarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}}},"required":["labels","series"],"additionalProperties":false,"description":"Spider/web chart; use for comparing multiple variables across one or more entities"},"PieChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}},"variant":{"type":"string","enum":["pie","donut"]},"appearance":{"type":"string","enum":["circular","semiCircular"]}},"required":["labels","values"],"additionalProperties":false,"description":"Circular slices; use plucked arrays: PieChart(data.categories, data.values)"},"RadialChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}}},"required":["labels","values"],"additionalProperties":false,"description":"Radial bars; use plucked arrays: RadialChart(data.categories, data.values)"},"SingleStackedBarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}}},"required":["labels","values"],"additionalProperties":false,"description":"Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)"},"ScatterChart":{"type":"object","properties":{"datasets":{"type":"array","items":{"$ref":"#/$defs/ScatterSeries"}},"xLabel":{"type":"string"},"yLabel":{"type":"string"}},"required":["datasets"],"additionalProperties":false,"description":"X/Y scatter plot; use for correlations, distributions, and clustering"},"ScatterSeries":{"type":"object","properties":{"name":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/$defs/Point"}}},"required":["name","points"],"additionalProperties":false,"description":"Named dataset"},"Point":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}},"required":["x","y"],"additionalProperties":false,"description":"Data point with numeric coordinates"},"AreaChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["linear","natural","step"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Filled area under lines; use for cumulative totals or volume trends over time"},"BarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["grouped","stacked"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Vertical bars; use for comparing values across categories with one or more series"},"LineChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["linear","natural","step"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Lines over categories; use for trends and continuous data over time"},"Table":{"type":"object","properties":{"columns":{"type":"array","items":{"$ref":"#/$defs/Col"}}},"required":["columns"],"additionalProperties":false,"description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"type":"object","properties":{"label":{"type":"string"},"data":{},"type":{"type":"string","enum":["string","number","action"]}},"required":["label","data"],"additionalProperties":false,"description":"Column definition — holds label + data array"},"TagBlock":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"}},"size":{"type":"string","enum":["sm","md","lg"]}},"required":["tags"],"additionalProperties":false,"description":"tags is an array of strings; optional size sm | md | lg"},"Form":{"type":"object","properties":{"name":{"type":"string"},"buttons":{"$ref":"#/$defs/Buttons"},"fields":{"default":[],"type":"array","items":{"$ref":"#/$defs/FormControl"}}},"required":["name","buttons","fields"],"additionalProperties":false,"description":"Form container with fields and explicit action buttons"},"Buttons":{"type":"object","properties":{"buttons":{"type":"array","items":{"$ref":"#/$defs/Button"}},"direction":{"type":"string","enum":["row","column"]}},"required":["buttons"],"additionalProperties":false,"description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"Button":{"type":"object","properties":{"label":{"type":"string"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"variant":{"type":"string","enum":["primary","secondary","tertiary"]},"type":{"type":"string","enum":["normal","destructive"]},"size":{"type":"string","enum":["extra-small","small","medium","large"]}},"required":["label"],"additionalProperties":false,"description":"Clickable button"},"FormControl":{"type":"object","properties":{"label":{"type":"string"},"input":{"anyOf":[{"$ref":"#/$defs/Input"},{"$ref":"#/$defs/TextArea"},{"$ref":"#/$defs/Select"},{"$ref":"#/$defs/DatePicker"},{"$ref":"#/$defs/Slider"},{"$ref":"#/$defs/CheckBoxGroup"},{"$ref":"#/$defs/RadioGroup"},{"$ref":"#/$defs/Chips"},{"$ref":"#/$defs/OptionCards"}]},"hint":{"type":"string"}},"required":["label","input"],"additionalProperties":false,"description":"Field with label, input component, and optional hint text"},"Input":{"type":"object","properties":{"name":{"type":"string"},"placeholder":{"type":"string"},"type":{"type":"string","enum":["text","email","password","number","url"]},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name"],"additionalProperties":false},"TextArea":{"type":"object","properties":{"name":{"type":"string"},"placeholder":{"type":"string"},"rows":{"type":"number"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name"],"additionalProperties":false},"Select":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/SelectItem"}},"placeholder":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"},"size":{"type":"string","enum":["small","medium","large"]}},"required":["name","items"],"additionalProperties":false},"SelectItem":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}},"required":["value","label"],"additionalProperties":false,"description":"Option for Select"},"DatePicker":{"type":"object","properties":{"name":{"type":"string"},"mode":{"type":"string","enum":["single","range"]},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{}},"required":["name"],"additionalProperties":false},"Slider":{"type":"object","properties":{"name":{"type":"string"},"variant":{"type":"string","enum":["continuous","discrete"]},"min":{"type":"number"},"max":{"type":"number"},"step":{"type":"number"},"defaultValue":{"type":"array","items":{"type":"number"}},"label":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"array","items":{"type":"number"}}},"required":["name","variant","min","max"],"additionalProperties":false,"description":"Numeric slider input; supports continuous and discrete (stepped) variants"},"CheckBoxGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/CheckBoxItem"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"boolean"}}},"required":["name","items"],"additionalProperties":false},"CheckBoxItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"},"defaultChecked":{"type":"boolean"}},"required":["label","description","name"],"additionalProperties":false},"RadioGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/RadioItem"}},"defaultValue":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name","items"],"additionalProperties":false},"RadioItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"value":{"type":"string"}},"required":["label","description","value"],"additionalProperties":false},"Chips":{"type":"object","properties":{"name":{"type":"string"},"type":{"default":"multiple","type":"string","enum":["single","multiple"]},"items":{"default":[],"type":"array","items":{"$ref":"#/$defs/ChipItem"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"defaultValue":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}},"required":["name","type","items"],"additionalProperties":false,"description":"A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`."},"ChipItem":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"disabled":{"type":"boolean"}},"required":["value","label"],"additionalProperties":false,"description":"A single selectable chip inside a Chips group, with a value, label and optional icon."},"Icon":{"type":"object","properties":{"name":{"type":"string"},"category":{"type":"string"}},"required":["name"],"additionalProperties":false,"description":"A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve."},"OptionCards":{"type":"object","properties":{"name":{"type":"string"},"type":{"default":"single","type":"string","enum":["single","multiple"]},"items":{"default":[],"type":"array","items":{"$ref":"#/$defs/OptionCard"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"defaultValue":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}},"required":["name","type","items"],"additionalProperties":false,"description":"A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`."},"OptionCard":{"type":"object","properties":{"value":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"topContent":{"anyOf":[{"$ref":"#/$defs/Icon"},{"$ref":"#/$defs/Image"}]},"disabled":{"type":"boolean"}},"required":["value","title"],"additionalProperties":false,"description":"A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top."},"IconButton":{"type":"object","properties":{"name":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"variant":{"type":"string","enum":["primary","secondary","tertiary"]},"size":{"type":"string","enum":["extra-small","small","medium","large"]},"shape":{"type":"string","enum":["square","circle"]}},"required":["name","icon"],"additionalProperties":false,"description":"Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click."},"Steps":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/StepsItem"}}},"required":["items"],"additionalProperties":false,"description":"Step-by-step guide"},"StepsItem":{"type":"object","properties":{"title":{"type":"string"},"details":{"type":"string"}},"required":["title","details"],"additionalProperties":false,"description":"title and details text for one step"},"InlineHeader":{"type":"object","properties":{"heading":{"type":"string"},"description":{"type":"string"}},"required":["heading"],"additionalProperties":false,"description":"Compact section heading with an optional one-line description, for use inside cards."},"EntityList":{"type":"object","properties":{"rows":{"default":[],"type":"array","items":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false}},"size":{"default":"default","type":"string","enum":["small","default"]},"header":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false},"footer":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false}},"required":["rows","size"],"additionalProperties":false,"description":"Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers."},"EditableTable":{"type":"object","properties":{"name":{"default":"","type":"string"},"columns":{"default":[],"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["text","number","date-single","select","url"]},"key":{"default":"default","type":"string"},"header":{"default":"","type":"string"},"width":{"type":"number"},"options":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}},"required":["value","label"],"additionalProperties":false}}},"required":["type","key","header"],"additionalProperties":false}},"data":{"default":[],"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"values":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}}},"required":["id","values"],"additionalProperties":false}}},"required":["name","columns","data"],"additionalProperties":false,"description":"Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field"},"SnippetCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/SnippetCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action."},"SnippetCardItem":{"type":"object","properties":{"id":{"type":"string"},"lhs":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"}]},"rhs":{"anyOf":[{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/BoldText"}]}},"required":["lhs"],"additionalProperties":false,"description":"One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)."},"IconText":{"type":"object","properties":{"icon":{"$ref":"#/$defs/Icon"},"iconVariant":{"default":"neutral","type":"string","enum":["neutral","info","success","warning","danger","inverted","filled","soft"]},"iconSize":{"default":"m","type":"string","enum":["xs","s","m","l","xl","sm","md","lg"]},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"},"layout":{"default":"horizontal","type":"string","enum":["horizontal","vertical"]}},"required":["icon","iconVariant","iconSize","title","bold","layout"],"additionalProperties":false,"description":"An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color."},"ImageText":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"},"layout":{"default":"horizontal","type":"string","enum":["horizontal","vertical"]},"imageSize":{"type":"number"}},"required":["src","title","bold","layout"],"additionalProperties":false,"description":"A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL."},"Text":{"type":"object","properties":{"variant":{"default":"text","type":"string","enum":["text","number"]},"value":{"type":"string"},"subtext":{"type":"string"},"subtextVariant":{"default":"text","type":"string","enum":["text","number","metric"]},"size":{"default":"sm","type":"string","enum":["xs","sm","md","lg"]}},"required":["variant","value","subtextVariant","size"],"additionalProperties":false,"description":"Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"BoldText":{"type":"object","properties":{"variant":{"default":"text","type":"string","enum":["text","number"]},"value":{"type":"string"},"subtext":{"type":"string"},"subtextVariant":{"default":"text","type":"string","enum":["text","number","metric"]},"size":{"default":"sm","type":"string","enum":["xs","sm","md","lg"]}},"required":["variant","value","subtextVariant","size"],"additionalProperties":false,"description":"Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"OverviewCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/OverviewCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action."},"OverviewCardItem":{"type":"object","properties":{"id":{"type":"string"},"top":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"},{"$ref":"#/$defs/Text"}]},"bottom":{"$ref":"#/$defs/MetricIndicatorInline"}},"required":["top"],"additionalProperties":false,"description":"One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom."},"MetricIndicatorInline":{"type":"object","properties":{"value":{"type":"string"},"subtext":{"type":"string"},"trend":{"type":"object","properties":{"direction":{"type":"string","enum":["up","down"]},"value":{"type":"number"}},"required":["direction","value"],"additionalProperties":false}},"required":["value"],"additionalProperties":false,"description":"Headline metric value with an optional +/- percentage trend and subtext, all on one line."},"ContextCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/ContextCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable."},"ContextCardItem":{"type":"object","properties":{"id":{"type":"string"},"title":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/Tag"}]},"body":{"type":"string"},"bgColor":{"type":"string","enum":["gray"]},"bgImageSrc":{"type":"string"},"bgImageAlt":{"type":"string"}},"required":["title"],"additionalProperties":false,"description":"A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image."},"Tag":{"type":"object","properties":{"text":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"size":{"type":"string","enum":["sm","md","lg"]},"variant":{"type":"string","enum":["neutral","info","success","warning","danger"]}},"required":["text"],"additionalProperties":false,"description":"Styled tag/badge with optional Icon and variant"},"CompositeCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/CompositeCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable."},"CompositeCardItem":{"type":"object","properties":{"id":{"type":"string"},"header":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"},{"$ref":"#/$defs/ImageTextLarge"},{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/Image"}]},"body":{"default":[],"type":"array","items":{"anyOf":[{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/BoldText"},{"$ref":"#/$defs/MetricIndicatorInline"},{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/ListBlock"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/EntityList"}]}},"footer":{"type":"object","properties":{"price":{"anyOf":[{"$ref":"#/$defs/BoldText"},{"$ref":"#/$defs/MetricIndicatorWithStrikethrough"}]},"button":{"$ref":"#/$defs/Button"}},"additionalProperties":false}},"required":["body"],"additionalProperties":false,"description":"A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer."},"ImageTextLarge":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"}},"required":["src","title","bold"],"additionalProperties":false,"description":"A full-width banner image above a bold title and optional subtitle. src must be a real image URL."},"ListBlock":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/ListItem"}},"variant":{"type":"string","enum":["number","image"]},"size":{"type":"string","enum":["default","small"]}},"required":["items"],"additionalProperties":false,"description":"A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list."},"ListItem":{"type":"object","properties":{"title":{"type":"string"},"subtitle":{"type":"string"},"image":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"}},"required":["src","alt"],"additionalProperties":false},"actionLabel":{"type":"string"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]}},"required":["title"],"additionalProperties":false,"description":"Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable."},"MetricIndicatorWithStrikethrough":{"type":"object","properties":{"value":{"type":"string"},"subtext":{"type":"string"},"previousValue":{"type":"string"},"trend":{"type":"object","properties":{"direction":{"type":"string","enum":["up","down"]},"value":{"type":"number"}},"required":["direction","value"],"additionalProperties":false}},"required":["value"],"additionalProperties":false,"description":"Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below."},"VisualCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/VisualCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable."},"VisualCardItem":{"type":"object","properties":{"body":{"$ref":"#/$defs/BoldText"},"id":{"type":"string"},"bgImageSrc":{"type":"string"},"tag":{"$ref":"#/$defs/Tag"},"bgImageAlt":{"type":"string"}},"required":["body"],"additionalProperties":false,"description":"A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)."},"Tabs":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/TabItem"}}},"required":["items"],"additionalProperties":false,"description":"Tabbed container"},"TabItem":{"type":"object","properties":{"value":{"type":"string"},"trigger":{"type":"string"},"content":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}}},"required":["value","trigger","content"],"additionalProperties":false,"description":"value is unique id, trigger is tab label, content is array of components"},"Carousel":{"type":"object","properties":{"children":{"type":"array","items":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}}},"variant":{"type":"string","enum":["card","sunk"]}},"required":["children"],"additionalProperties":false,"description":"Horizontal scrollable carousel"},"Stack":{"type":"object","properties":{"children":{"type":"array","items":{}},"direction":{"type":"string","enum":["row","column"]},"gap":{"type":"string","enum":["none","xs","s","m","l","xl","2xl"]},"align":{"type":"string","enum":["start","center","end","stretch","baseline"]},"justify":{"type":"string","enum":["start","center","end","between","around","evenly"]},"wrap":{"type":"boolean"}},"required":["children"],"additionalProperties":false,"description":"Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"."},"Slice":{"type":"object","properties":{"category":{"type":"string"},"value":{"type":"number"}},"required":["category","value"],"additionalProperties":false,"description":"One slice with label and numeric value"},"Label":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"],"additionalProperties":false,"description":"Text label"},"SwitchGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/SwitchItem"}},"variant":{"type":"string","enum":["clear","card","sunk"]},"value":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"boolean"}}},"required":["name","items"],"additionalProperties":false,"description":"Group of switch toggles"},"SwitchItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"},"defaultChecked":{"type":"boolean"}},"required":["name"],"additionalProperties":false,"description":"Individual switch toggle"},"Accordion":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/AccordionItem"}}},"required":["items"],"additionalProperties":false,"description":"Collapsible sections"},"AccordionItem":{"type":"object","properties":{"value":{"type":"string"},"trigger":{"type":"string"},"content":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}}},"required":["value","trigger","content"],"additionalProperties":false,"description":"value is unique id, trigger is section title"},"Modal":{"type":"object","properties":{"title":{"type":"string"},"open":{"type":"boolean"},"children":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}},"size":{"type":"string","enum":["sm","md","lg"]}},"required":["title","children"],"additionalProperties":false,"description":"Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children."}}} } diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json index 6c3943c3c8..f12909222c 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/parser.json @@ -1,7142 +1,67 @@ [ - { - "name": "chat-example-1", - "schema": "chat", - "input": "Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "CardHeader", - "props": { - "title": "Paris", - "subtitle": "The City of Light · France's Eternal Capital" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "header" - }, - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]." - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "intro" - }, - { - "type": "element", - "typeName": "ContextCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "ContextCardItem", - "props": { - "id": "art-museums", - "title": "Art & Museums", - "body": "143 museums including the Louvre & newly reopened Grand Palais.", - "bgColor": "gray", - "bgImageSrc": "https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "h1" - }, - { - "type": "element", - "typeName": "ContextCardItem", - "props": { - "id": "gastronomy", - "title": "Gastronomy", - "body": "9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.", - "bgColor": "gray" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "h2" - }, - { - "type": "element", - "typeName": "ContextCardItem", - "props": { - "id": "fashion-capital", - "title": "Fashion Capital", - "body": "Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.", - "bgColor": "gray", - "bgImageSrc": "https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "h3" - } - ], - "layout": "grid", - "responsive": true, - "action": { - "type": "continue_conversation", - "context": "Tell me more about this aspect of Paris" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "highlights" - }, - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "Paris by the Numbers", - "description": "Key visitor statistics" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "statsHeader" - }, - { - "type": "element", - "typeName": "OverviewCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "OverviewCardItem", - "props": { - "id": "annual-visitors", - "top": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "users", - "category": "people" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov1icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Annual Visitors", - "subtitle": "2024 arrivals", - "bold": false, - "layout": "vertical" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov1top" - }, - "bottom": { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "48.7M", - "subtext": "tourists", - "trend": { - "direction": "up", - "value": 2.5 - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov1metric" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov1" - }, - { - "type": "element", - "typeName": "OverviewCardItem", - "props": { - "id": "museums-monuments", - "top": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "landmark", - "category": "buildings" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov2icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Museums & Monuments", - "subtitle": "Cultural sites", - "bold": false, - "layout": "vertical" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov2top" - }, - "bottom": { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "2,370+", - "subtext": "across the city" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov2metric" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov2" - }, - { - "type": "element", - "typeName": "OverviewCardItem", - "props": { - "id": "tourism-revenue", - "top": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "circle-dollar-sign", - "category": "finance" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov3icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Tourism Revenue", - "subtitle": "2024 estimate", - "bold": false, - "layout": "vertical" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov3top" - }, - "bottom": { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "€23.4B", - "subtext": "generated" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov3metric" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ov3" - } - ], - "layout": "grid", - "responsive": true - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "statsCards" - }, - { - "type": "element", - "typeName": "SectionBlock", - "props": { - "sections": [ - { - "type": "element", - "typeName": "SectionItem", - "props": { - "value": "landmarks", - "trigger": "Iconic Landmarks", - "content": [ - { - "type": "element", - "typeName": "VisualCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Eiffel Tower", - "subtext": "Open daily 9am–midnight", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm1body" - }, - "id": "eiffel-tower", - "bgImageSrc": "https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "Must-See", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "star", - "category": "shapes" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm1tagIcon" - }, - "size": "sm", - "variant": "info" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm1tag" - }, - "bgImageAlt": "Aerial view of the Eiffel Tower" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm1" - }, - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "The Louvre", - "subtext": "World's largest art museum", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm2body" - }, - "id": "the-louvre", - "bgImageSrc": "https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "8.9M visits/yr", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "trending-up", - "category": "charts" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm2tagIcon" - }, - "size": "sm", - "variant": "success" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm2tag" - }, - "bgImageAlt": "Exterior of the Louvre museum" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm2" - }, - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Notre-Dame", - "subtext": "Fully restored cathedral", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm3body" - }, - "id": "notre-dame", - "bgImageSrc": "https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "Reopened 2024", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "hammer", - "category": "tools" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm3tagIcon" - }, - "size": "sm", - "variant": "warning" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm3tag" - }, - "bgImageAlt": "Notre-Dame cathedral facade" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm3" - }, - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Palace of Versailles", - "subtext": "Royal gardens & grand halls", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm4body" - }, - "id": "versailles", - "bgImageSrc": "https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "Day Trip", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "train-front", - "category": "travel" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm4tagIcon" - }, - "size": "sm", - "variant": "neutral" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm4tag" - }, - "bgImageAlt": "Latona Fountain at Versailles" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "lm4" - } - ], - "layout": "carousel", - "responsive": true, - "action": { - "type": "continue_conversation", - "context": "Tell me more about this Paris landmark" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "landmarksCarousel" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "secLandmarks" - }, - { - "type": "element", - "typeName": "SectionItem", - "props": { - "value": "food", - "trigger": "Food & Drink", - "content": [ - { - "type": "element", - "typeName": "ContextCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "ContextCardItem", - "props": { - "id": "bistros", - "title": "Bistros", - "body": "Classic French fare — try Les Arlots for confit beef cheeks.", - "bgColor": "gray", - "bgImageSrc": "https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "f1" - }, - { - "type": "element", - "typeName": "ContextCardItem", - "props": { - "id": "fine-dining", - "title": "Fine Dining", - "body": "Septime leads a new wave of creative Michelin-starred cuisine.", - "bgColor": "gray", - "bgImageSrc": "https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "f2" - }, - { - "type": "element", - "typeName": "ContextCardItem", - "props": { - "id": "bakeries", - "title": "Bakeries", - "body": "Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.", - "bgColor": "gray", - "bgImageSrc": "https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "f3" - } - ], - "layout": "grid", - "responsive": true, - "action": { - "type": "continue_conversation", - "context": "Tell me more about eating and drinking in Paris" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "foodCards" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "secFood" - }, - { - "type": "element", - "typeName": "SectionItem", - "props": { - "value": "when", - "trigger": "Best Time to Visit", - "content": [ - { - "type": "element", - "typeName": "Tabs", - "props": { - "items": [ - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "spring", - "trigger": "Spring", - "content": [ - { - "type": "element", - "typeName": "ListBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "ListItem", - "props": { - "title": "Cherry blossoms at Parc de Sceaux", - "subtitle": "March – May", - "image": null, - "actionLabel": null, - "action": { - "type": "continue_conversation", - "context": "Tell me about cherry blossom season in Paris" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "sp1" - }, - { - "type": "element", - "typeName": "ListItem", - "props": { - "title": "Picnics along the Seine & in city parks", - "subtitle": "Warm, lively atmosphere", - "image": null, - "actionLabel": null, - "action": { - "type": "continue_conversation", - "context": "Where are the best picnic spots in Paris?" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "sp2" - }, - { - "type": "element", - "typeName": "ListItem", - "props": { - "title": "Fewer crowds than summer", - "subtitle": "Ideal for sightseeing", - "image": null, - "actionLabel": null, - "action": { - "type": "continue_conversation", - "context": "How busy is Paris in spring?" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "sp3" - } - ], - "variant": "number" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "springList" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabSpring" - }, - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "summer", - "trigger": "Summer", - "content": [ - { - "type": "element", - "typeName": "ListBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "ListItem", - "props": { - "title": "Swim in the Seine — open July & August 2026", - "subtitle": "First time in 102 years", - "image": null, - "actionLabel": null, - "action": { - "type": "continue_conversation", - "context": "Tell me about swimming in the Seine" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "su1" - }, - { - "type": "element", - "typeName": "ListItem", - "props": { - "title": "Open-air cinema at Parc de la Villette", - "subtitle": "Free films under the stars", - "image": null, - "actionLabel": null, - "action": { - "type": "continue_conversation", - "context": "Tell me about the open-air cinema at Parc de la Villette" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "su2" - }, - { - "type": "element", - "typeName": "ListItem", - "props": { - "title": "Bastille Day celebrations on July 14", - "subtitle": "Fireworks at the Eiffel Tower", - "image": null, - "actionLabel": null, - "action": { - "type": "continue_conversation", - "context": "What happens in Paris on Bastille Day?" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "su3" - } - ], - "variant": "number" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "summerList" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabSummer" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "whenTabs" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "secWhen" - } - ], - "isFoldable": false - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "sectionsBlock" - }, - { - "type": "element", - "typeName": "Buttons", - "props": { - "buttons": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Plan a Trip to Paris", - "action": { - "type": "continue_conversation", - "context": "Help me plan a trip to Paris" - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btn1" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Best Hotels in Paris", - "action": { - "type": "continue_conversation", - "context": "Show me the best hotels in Paris" - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btn2" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Build a Paris Itinerary", - "action": { - "type": "continue_conversation", - "context": "Build a 5-day Paris itinerary for me" - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btn3" - } - ], - "direction": "row" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "actionBtns" - } - ], - "sources": [ - { - "title": "Paris Travel Guide 2025", - "sourceName": "Travel and Tour World", - "url": "https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/" - }, - { - "title": "Best Things to Do in Paris 2026", - "sourceName": "Time Out Paris", - "url": "http://www.timeout.fr/paris/en/for-tourists" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 63, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "chat-example-2", - "schema": "chat", - "input": "Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "CardHeader", - "props": { - "title": "Analytics Dashboard", - "subtitle": "April 2026 · Business Performance Overview" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "pageHeader" - }, - { - "type": "element", - "typeName": "SnippetCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "total-revenue", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "circle-dollar-sign", - "category": "finance" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Total Revenue", - "subtitle": "Month to date", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "$284,500", - "subtext": "+12.4%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1" - }, - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "active-users", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "users", - "category": "people" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Active Users", - "subtitle": "Monthly active users", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "47,320", - "subtext": "+6.8%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2" - }, - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "conversion-rate", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "trending-up", - "category": "charts" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Conversion Rate", - "subtitle": "Avg. this month", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "5.7%", - "subtext": "+0.9%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3" - }, - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "churn-rate", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "user-minus", - "category": "people" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi4icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Churn Rate", - "subtitle": "Monthly customer churn", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi4lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "2.1%", - "subtext": "-0.4%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi4rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi4" - } - ], - "layout": "grid", - "responsive": true - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpiBlock" - }, - { - "type": "element", - "typeName": "SectionBlock", - "props": { - "sections": [ - { - "type": "element", - "typeName": "SectionItem", - "props": { - "value": "users", - "trigger": "User Activity", - "content": [ - { - "type": "element", - "typeName": "Tabs", - "props": { - "items": [ - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "growth", - "trigger": "User Growth", - "content": [ - { - "type": "element", - "typeName": "LineChart", - "props": { - "labels": [ - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - "Jan", - "Feb", - "Mar", - "Apr" - ], - "series": [ - { - "type": "element", - "typeName": "Series", - "props": { - "category": "DAU", - "values": [ - 5.1, - 5.4, - 5.8, - 6.2, - 6.7, - 7.1, - 7.6, - 8, - 8.4, - 8.9, - 9.3, - 9.8 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "dauSeries" - }, - { - "type": "element", - "typeName": "Series", - "props": { - "category": "MAU", - "values": [ - 28.4, - 30.1, - 31.8, - 33.5, - 35.2, - 37.1, - 38.8, - 40.4, - 42.1, - 43.9, - 45.6, - 47.3 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "mauSeries" - } - ], - "variant": "natural", - "xLabel": "Month", - "yLabel": "Users (k)" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "growthChart" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabGrowth" - }, - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "retention", - "trigger": "Cohort Retention", - "content": [ - { - "type": "element", - "typeName": "LineChart", - "props": { - "labels": [ - "Month 0", - "Month 1", - "Month 2", - "Month 3", - "Month 4", - "Month 5", - "Month 6" - ], - "series": [ - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Jan Cohort", - "values": [ - 100, - 80, - 70, - 62, - 56, - 51, - 47 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "cohortJan" - }, - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Feb Cohort", - "values": [ - 100, - 83, - 73, - 65, - 59, - 54, - 50 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "cohortFeb" - }, - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Mar Cohort", - "values": [ - 100, - 86, - 76, - 68, - 62, - 0, - 0 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "cohortMar" - } - ], - "variant": "natural", - "xLabel": "Month Since Signup", - "yLabel": "Retention (%)" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "retentionChart" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabRetention" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "userTabs" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "secUsers" - }, - { - "type": "element", - "typeName": "SectionItem", - "props": { - "value": "channels", - "trigger": "Acquisition Channels", - "content": [ - { - "type": "element", - "typeName": "Tabs", - "props": { - "items": [ - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "channel-bar", - "trigger": "Revenue by Channel", - "content": [ - { - "type": "element", - "typeName": "HorizontalBarChart", - "props": { - "labels": [ - "Organic Search", - "Paid Ads", - "Referral Program", - "Partner Network", - "Direct / Brand", - "Email Campaigns" - ], - "series": [ - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Revenue ($k)", - "values": [ - 82.4, - 68.1, - 54.6, - 38.2, - 26.8, - 14.4 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "channelSeries" - } - ], - "variant": "grouped", - "xLabel": "Revenue ($k)", - "yLabel": "Channel" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "channelBarChart" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabChannelBar" - }, - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "channel-table", - "trigger": "Full Breakdown", - "content": [ - { - "type": "element", - "typeName": "Table", - "props": { - "columns": [ - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Channel", - "data": [ - "Organic Search", - "Paid Ads", - "Referral Program", - "Partner Network", - "Direct / Brand", - "Email Campaigns" - ], - "type": "string" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "colChannel" - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Leads", - "data": [ - 4210, - 3180, - 2050, - 1120, - 1290, - 820 - ], - "type": "number" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "colLeads" - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Conv. Rate", - "data": [ - "6.4%", - "5.1%", - "9.4%", - "11.8%", - "5.8%", - "8.1%" - ], - "type": "string" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "colConv" - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "CAC ($)", - "data": [ - 188, - 395, - 132, - 109, - 218, - 154 - ], - "type": "number" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "colCac" - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Revenue ($k)", - "data": [ - 82.4, - 68.1, - 54.6, - 38.2, - 26.8, - 14.4 - ], - "type": "number" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "colRevenue" - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Status", - "data": [ - "Scaling", - "Optimizing", - "Scaling", - "Growing", - "Stable", - "Stable" - ], - "type": "string" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "colStatus" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "channelTable" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabChannelTable" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "channelTabs" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "secChannels" - } - ], - "isFoldable": false - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "sections" - }, - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "Support Health & Marketing ROI", - "description": "Click a card to explore deeper insights" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "deepDiveHeader" - }, - { - "type": "element", - "typeName": "CompositeCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "CompositeCardItem", - "props": { - "id": "support-health", - "header": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "headphones", - "category": "communication" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "supportIcon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Support Health", - "subtitle": "Ticket volume & resolution trends", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "supportHeader" - }, - "body": [ - { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "94.2% CSAT", - "subtext": "Customer Satisfaction Score", - "trend": { - "direction": "up", - "value": 2.1 - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "supportMetric" - }, - { - "type": "element", - "typeName": "BarChart", - "props": { - "labels": [ - "Jan", - "Feb", - "Mar", - "Apr" - ], - "series": [ - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Opened", - "values": [ - 341, - 327, - 308, - 289 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "openSeries" - }, - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Resolved", - "values": [ - 319, - 318, - 301, - 283 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "resolvedSeries" - } - ], - "variant": "grouped", - "xLabel": "Month", - "yLabel": "Tickets" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "supportChart" - }, - { - "type": "element", - "typeName": "EntityList", - "props": { - "rows": [ - { - "left": "Avg. Resolution Time", - "right": "4h 12m", - "rightVariant": "text" - }, - { - "left": "First Contact Resolution", - "right": "78.4%", - "rightVariant": "number" - }, - { - "left": "Escalation Rate", - "right": "6.2%", - "rightVariant": "number" - } - ], - "size": "small" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "supportList" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "cardSupport" - }, - { - "type": "element", - "typeName": "CompositeCardItem", - "props": { - "id": "marketing-roi", - "header": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "megaphone", - "category": "communication" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "marketingIcon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Marketing ROI", - "subtitle": "Spend vs. pipeline generated", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "marketingHeader" - }, - "body": [ - { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "3.8x Blended ROI", - "subtext": "Return on Ad Spend", - "trend": { - "direction": "up", - "value": 0.4 - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "marketingMetric" - }, - { - "type": "element", - "typeName": "AreaChart", - "props": { - "labels": [ - "Jan", - "Feb", - "Mar", - "Apr" - ], - "series": [ - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Ad Spend", - "values": [ - 44, - 46.8, - 49.2, - 51.6 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "spendSeries" - }, - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Pipeline Generated", - "values": [ - 158.2, - 171.5, - 184.9, - 196.1 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "pipelineSeries" - } - ], - "variant": "natural", - "xLabel": "Month", - "yLabel": "Value ($k)" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "marketingChart" - }, - { - "type": "element", - "typeName": "EntityList", - "props": { - "rows": [ - { - "left": "Total Ad Spend (Apr)", - "right": "$51,600", - "rightVariant": "number" - }, - { - "left": "Cost per Lead", - "right": "$48.20", - "rightVariant": "number" - }, - { - "left": "Top Channel", - "right": "Organic Search", - "rightVariant": "text" - } - ], - "size": "small" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "marketingList" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "cardMarketing" - } - ], - "layout": "grid", - "responsive": true, - "action": { - "type": "continue_conversation", - "context": "Explore this deep-dive area in more detail" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "compositeCards" - }, - { - "type": "element", - "typeName": "Buttons", - "props": { - "buttons": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Break Down by Channel", - "action": { - "type": "continue_conversation", - "context": "Break down this month's revenue by acquisition channel" - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btnChannels" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Forecast Next Quarter", - "action": { - "type": "continue_conversation", - "context": "Forecast revenue and active users for next quarter" - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btnForecast" - } - ], - "direction": "row" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "actionButtons" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 74, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "chat-example-3", - "schema": "chat", - "input": "Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "CardHeader", - "props": { - "title": "Plan Your Trip", - "subtitle": "A few ideas to spark inspiration — then tell me your preferences" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "header" - }, - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Tap a style to jump straight in, or fill the quick form below for a tailored plan." - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "intro" - }, - { - "type": "element", - "typeName": "VisualCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Tropical Beach Escape", - "subtext": "Overwater villas & snorkeling", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp1body" - }, - "id": "inspo-beach", - "bgImageSrc": "https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "Relaxation", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "umbrella", - "category": "travel" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp1icon" - }, - "size": "sm", - "variant": "info" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp1tag" - }, - "bgImageAlt": "Maldives overwater villas" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp1" - }, - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Mountain Adventure", - "subtext": "Trekking & epic views", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp2body" - }, - "id": "inspo-mountain", - "bgImageSrc": "https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "Active", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "mountain", - "category": "nature" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp2icon" - }, - "size": "sm", - "variant": "warning" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp2tag" - }, - "bgImageAlt": "Trekking in the Peruvian Andes" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "insp2" - } - ], - "layout": "grid", - "responsive": true, - "action": { - "type": "continue_conversation", - "context": "Plan me a trip in this style with destinations, itinerary, and costs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "inspoCards" - }, - { - "type": "element", - "typeName": "Form", - "props": { - "name": "trip-planner", - "buttons": { - "type": "element", - "typeName": "Buttons", - "props": { - "buttons": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Plan My Trip", - "action": { - "type": "continue_conversation", - "context": "Help me plan a trip based on my form submission" - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btnSubmit" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Just Surprise Me", - "action": { - "type": "continue_conversation", - "context": "Skip the form and surprise me with a destination and itinerary" - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "btnSkip" - } - ], - "direction": "row" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "formButtons" - }, - "fields": [ - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Destination", - "input": { - "type": "element", - "typeName": "Input", - "props": { - "name": "destination", - "placeholder": "e.g. Tokyo, Japan — or leave blank", - "type": "text" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "destinationInput" - }, - "hint": "Leave blank if you'd like suggestions" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcDestination" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Travel Dates", - "input": { - "type": "element", - "typeName": "DatePicker", - "props": { - "name": "travel-dates", - "mode": "range", - "rules": { - "required": true - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "datesPicker" - }, - "hint": "Select your start and end dates" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcDates" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Number of Travellers", - "input": { - "type": "element", - "typeName": "Select", - "props": { - "name": "num-travellers", - "items": [ - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "1", - "label": "1 — Solo" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tr1" - }, - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "2", - "label": "2 — Couple" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tr2" - }, - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "3-4", - "label": "3–4 People" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tr3" - }, - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "5+", - "label": "5+ People" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tr4" - } - ], - "placeholder": "Select number of travellers", - "rules": { - "required": true - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "travellersSelect" - }, - "hint": "How many people are travelling?" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcTravellers" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Trip Type", - "input": { - "type": "element", - "typeName": "OptionCards", - "props": { - "name": "trip-type", - "type": "single", - "items": [ - { - "type": "element", - "typeName": "OptionCard", - "props": { - "value": "adventure", - "title": "Adventure", - "subtitle": "Hiking, trekking & outdoor activities", - "topContent": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "mountain", - "category": "nature" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc1icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc1" - }, - { - "type": "element", - "typeName": "OptionCard", - "props": { - "value": "beach", - "title": "Beach & Relaxation", - "subtitle": "Sun, sand & leisure", - "topContent": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "waves", - "category": "nature" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc2icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc2" - }, - { - "type": "element", - "typeName": "OptionCard", - "props": { - "value": "cultural", - "title": "Cultural & Historical", - "subtitle": "Museums, heritage & local experiences", - "topContent": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "landmark", - "category": "buildings" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc3icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc3" - }, - { - "type": "element", - "typeName": "OptionCard", - "props": { - "value": "city", - "title": "City Break", - "subtitle": "Urban exploration & nightlife", - "topContent": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "building-2", - "category": "buildings" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc4icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "oc4" - } - ], - "rules": { - "required": true - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tripTypeCards" - }, - "hint": "What kind of trip are you planning?" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcTripType" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Estimated Budget (per person)", - "input": { - "type": "element", - "typeName": "Slider", - "props": { - "name": "budget", - "variant": "discrete", - "min": 500, - "max": 10000, - "step": 500, - "defaultValue": [ - 2500 - ], - "label": "Budget (USD)" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "budgetSlider" - }, - "hint": "Drag to set your per-person budget in USD" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcBudget" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Accommodation Preference", - "input": { - "type": "element", - "typeName": "Chips", - "props": { - "name": "accommodation", - "type": "multiple", - "items": [ - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "hotel", - "label": "Hotel", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "building", - "category": "buildings" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch1icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch1" - }, - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "resort", - "label": "Resort", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "umbrella", - "category": "travel" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch2icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch2" - }, - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "airbnb", - "label": "Vacation Rental", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "home", - "category": "home" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch3icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch3" - }, - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "camping", - "label": "Camping / Glamping", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "tent", - "category": "nature" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch4icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "ch4" - } - ], - "rules": {}, - "defaultValue": [ - "hotel" - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "stayChips" - }, - "hint": "Select all that apply" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcStay" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Special Requests or Notes", - "input": { - "type": "element", - "typeName": "TextArea", - "props": { - "name": "special-requests", - "placeholder": "e.g. vegetarian meals, wheelchair access, honeymoon surprise...", - "rows": 4 - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "notesArea" - }, - "hint": "Any dietary needs, accessibility requirements, or specific interests?" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fcNotes" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "form" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 50, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "chat-example-4", - "schema": "chat", - "input": "Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "CardHeader", - "props": { - "title": "Retro-Energetic Indian Tracks", - "subtitle": "New Hindi releases with 80s/90s dance DNA" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "header" - }, - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video." - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "intro" - }, - { - "type": "element", - "typeName": "VisualCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Tamma Tamma", - "subtext": "Dhurandhar · Ranveer Singh", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v1body" - }, - "id": "tamma", - "bgImageSrc": "https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "80s Electro-Disco", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "disc-3", - "category": "multimedia" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v1icon" - }, - "size": "sm", - "variant": "success" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v1tag" - }, - "bgImageAlt": "Tamma Tamma video poster" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v1" - }, - { - "type": "element", - "typeName": "VisualCardItem", - "props": { - "body": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "Sajan Re", - "subtext": "Nora Fatehi · Badshah", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v2body" - }, - "id": "sajan", - "bgImageSrc": "https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg", - "tag": { - "type": "element", - "typeName": "Tag", - "props": { - "text": "Synthwave Electro", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "music", - "category": "multimedia" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v2icon" - }, - "size": "sm", - "variant": "info" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v2tag" - }, - "bgImageAlt": "Sajan Re video poster" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "v2" - } - ], - "layout": "grid", - "responsive": true, - "action": { - "type": "continue_conversation", - "context": "Tell me more about this track and its retro influences" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "posters" - }, - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "Watch the Exact Videos", - "description": "Each button opens that track's official video" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "linksHeader" - }, - { - "type": "element", - "typeName": "CompositeCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "CompositeCardItem", - "props": { - "id": "t-tamma", - "header": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "disc-3", - "category": "multimedia" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Tamma Tamma", - "subtitle": "Bappi Lahiri classic, electro-funk rework", - "bold": true, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1h" - }, - "body": [ - { - "type": "element", - "typeName": "Text", - "props": { - "variant": "text", - "value": "Heavy analog synths and brass over a fast disco groove.", - "subtext": "Retro Electro-Disco", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1body" - }, - { - "type": "element", - "typeName": "TagBlock", - "props": { - "tags": [ - "2026 Film Hit", - "Peak Party" - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1tags" - } - ], - "footer": { - "button": { - "type": "element", - "typeName": "Button", - "props": { - "label": "Watch on YouTube", - "action": { - "type": "open_url", - "url": "https://www.youtube.com/watch?v=PQHeOb0Q9oo" - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1btn" - } - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1" - }, - { - "type": "element", - "typeName": "CompositeCardItem", - "props": { - "id": "t-sajan", - "header": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "music", - "category": "multimedia" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t2icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Sajan Re", - "subtitle": "Nora Fatehi · Badshah · Sanjoy", - "bold": true, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t2h" - }, - "body": [ - { - "type": "element", - "typeName": "Text", - "props": { - "variant": "text", - "value": "Synthwave melody hooks over a modern club beat.", - "subtext": "Retro-Fusion Electro", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t2body" - }, - { - "type": "element", - "typeName": "TagBlock", - "props": { - "tags": [ - "Club Anthem", - "Nora x Badshah" - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t2tags" - } - ], - "footer": { - "button": { - "type": "element", - "typeName": "Button", - "props": { - "label": "Watch on YouTube", - "action": { - "type": "open_url", - "url": "https://www.youtube.com/watch?v=COUSCnFazzc" - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t2btn" - } - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t2" - } - ], - "layout": "grid", - "responsive": true - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "trackCards" - } - ], - "sources": [ - { - "title": "Tamma Tamma (Full Video) - Dhurandhar", - "sourceName": "YouTube (T-Series)", - "url": "https://www.youtube.com/watch?v=PQHeOb0Q9oo" - }, - { - "title": "Sajan Re (Official Music Video)", - "sourceName": "YouTube (T-Series)", - "url": "https://www.youtube.com/watch?v=COUSCnFazzc" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 28, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "chat-example-5", - "schema": "chat", - "input": "Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Top Languages", - "size": "large-heavy" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "title" - }, - { - "type": "element", - "typeName": "Table", - "props": { - "columns": [ - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Language", - "data": [ - "Python", - "JavaScript", - "Java" - ] - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Users (M)", - "data": [ - 15.7, - 14.2, - 12.1 - ] - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Year", - "data": [ - 1991, - 1995, - 1995 - ] - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tbl" - }, - { - "type": "element", - "typeName": "FollowUpBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "FollowUpItem", - "props": { - "text": "Tell me more about Python" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fu1" - }, - { - "type": "element", - "typeName": "FollowUpItem", - "props": { - "text": "Show me a JavaScript comparison" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fu2" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "followUps" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 9, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "openui-example-1", - "schema": "openui", - "input": "Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]", - "expected": { - "root": { - "type": "element", - "typeName": "Stack", - "props": { - "children": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Top Languages", - "size": "large-heavy" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "title" - }, - { - "type": "element", - "typeName": "Table", - "props": { - "columns": [ - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Language", - "data": [ - "Python", - "JavaScript", - "Java", - "TypeScript", - "Go" - ] - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Users (M)", - "data": [ - 15.7, - 14.2, - 12.1, - 8.5, - 5.2 - ] - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Col", - "props": { - "label": "Year", - "data": [ - 1991, - 1995, - 1995, - 2012, - 2009 - ] - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tbl" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 6, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "openui-example-2", - "schema": "openui", - "input": "Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])", - "expected": { - "root": { - "type": "element", - "typeName": "Stack", - "props": { - "children": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Q4 Revenue", - "size": "large-heavy" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "title" - }, - { - "type": "element", - "typeName": "BarChart", - "props": { - "labels": [ - "Oct", - "Nov", - "Dec" - ], - "series": [ - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Product A", - "values": [ - 120, - 150, - 180 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "s1" - }, - { - "type": "element", - "typeName": "Series", - "props": { - "category": "Product B", - "values": [ - 90, - 110, - 140 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "s2" - } - ], - "variant": "grouped" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "chart" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 6, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "openui-example-3", - "schema": "openui", - "input": "Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Stack", - "props": { - "children": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Contact Us", - "size": "large-heavy" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "title" - }, - { - "type": "element", - "typeName": "Form", - "props": { - "name": "contact", - "buttons": { - "type": "element", - "typeName": "Buttons", - "props": { - "buttons": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Submit", - "action": { - "k": "Comp", - "name": "Action", - "args": [ - { - "k": "Arr", - "els": [ - { - "k": "Comp", - "name": "ToAssistant", - "args": [ - { - "k": "Str", - "v": "Submit" - } - ] - } - ] - } - ] - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Cancel", - "action": { - "k": "Comp", - "name": "Action", - "args": [ - { - "k": "Arr", - "els": [ - { - "k": "Comp", - "name": "ToAssistant", - "args": [ - { - "k": "Str", - "v": "Cancel" - } - ] - } - ] - } - ] - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "btns" - }, - "fields": [ - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Name", - "input": { - "type": "element", - "typeName": "Input", - "props": { - "name": "name", - "placeholder": "Your name", - "type": "text", - "rules": { - "required": true, - "minLength": 2 - } - }, - "partial": false, - "hasDynamicProps": false - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "nameField" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Email", - "input": { - "type": "element", - "typeName": "Input", - "props": { - "name": "email", - "placeholder": "you@example.com", - "type": "email", - "rules": { - "required": true, - "email": true - } - }, - "partial": false, - "hasDynamicProps": false - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "emailField" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Country", - "input": { - "type": "element", - "typeName": "Select", - "props": { - "name": "country", - "items": [ - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "us", - "label": "United States" - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "uk", - "label": "United Kingdom" - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "SelectItem", - "props": { - "value": "de", - "label": "Germany" - }, - "partial": false, - "hasDynamicProps": false - } - ], - "placeholder": "Select...", - "rules": { - "required": true - } - }, - "partial": false, - "hasDynamicProps": false - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "countryField" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Message", - "input": { - "type": "element", - "typeName": "TextArea", - "props": { - "name": "message", - "placeholder": "Tell us more...", - "rows": 4, - "rules": { - "required": true, - "minLength": 10 - } - }, - "partial": false, - "hasDynamicProps": false - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "msgField" - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "form" - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 9, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "openui-example-4", - "schema": "openui", - "input": "Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]", - "expected": { - "root": { - "type": "element", - "typeName": "Stack", - "props": { - "children": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "React vs Vue", - "size": "large-heavy" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "title" - }, - { - "type": "element", - "typeName": "Tabs", - "props": { - "items": [ - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "react", - "trigger": "React", - "content": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "React is a library by Meta for building UIs." - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Callout", - "props": { - "variant": "info", - "title": "Note", - "description": "React uses JSX syntax." - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabReact" - }, - { - "type": "element", - "typeName": "TabItem", - "props": { - "value": "vue", - "trigger": "Vue", - "content": [ - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Vue is a progressive framework by Evan You." - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Callout", - "props": { - "variant": "success", - "title": "Tip", - "description": "Vue has a gentle learning curve." - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabVue" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tabs" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 7, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "openui-example-5", - "schema": "openui", - "input": "Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")", - "expected": { - "root": { - "type": "element", - "typeName": "Stack", - "props": { - "children": [ - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "This Month", - "description": "Key account metrics" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpiHeader" - }, - { - "type": "element", - "typeName": "SnippetCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "revenue", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "circle-dollar-sign", - "category": "finance" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Revenue", - "subtitle": "Month to date", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "$48,200", - "subtext": "+8.1%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi1" - }, - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "active-users", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "users", - "category": "people" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Active Users", - "subtitle": "This month", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "1,204", - "subtext": "+3.4%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi2" - }, - { - "type": "element", - "typeName": "SnippetCardItem", - "props": { - "id": "churn", - "lhs": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "user-minus", - "category": "people" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Churn", - "subtitle": "This month", - "bold": false, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3lhs" - }, - "rhs": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "number", - "value": "1.8%", - "subtext": "-0.3%", - "subtextVariant": "metric", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3rhs" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpi3" - } - ], - "layout": "grid", - "responsive": true - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "kpiBlock" - }, - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "Top Products", - "description": "By units sold" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "productsHeader" - }, - { - "type": "element", - "typeName": "CompositeCardBlock", - "props": { - "items": [ - { - "type": "element", - "typeName": "CompositeCardItem", - "props": { - "id": "widget-pro", - "header": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "package", - "category": "shopping" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "p1icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Widget Pro", - "subtitle": "Best seller", - "bold": true, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "p1header" - }, - "body": [ - { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "2,410 units", - "subtext": "Sold this month", - "trend": { - "direction": "up", - "value": 12 - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "p1body" - } - ], - "footer": { - "price": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "$29.00", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false - }, - "button": { - "type": "element", - "typeName": "Button", - "props": { - "label": "View Details", - "action": { - "k": "Comp", - "name": "Action", - "args": [ - { - "k": "Arr", - "els": [ - { - "k": "Comp", - "name": "ToAssistant", - "args": [ - { - "k": "Str", - "v": "Show details for Widget Pro" - } - ] - } - ] - } - ] - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "p1btn" - } - } - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "p1" - }, - { - "type": "element", - "typeName": "CompositeCardItem", - "props": { - "id": "widget-mini", - "header": { - "type": "element", - "typeName": "IconText", - "props": { - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "box", - "category": "shopping" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "p2icon" - }, - "iconVariant": "neutral", - "iconSize": "m", - "title": "Widget Mini", - "subtitle": "New arrival", - "bold": true, - "layout": "horizontal" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "p2header" - }, - "body": [ - { - "type": "element", - "typeName": "MetricIndicatorInline", - "props": { - "value": "980 units", - "subtext": "Sold this month", - "trend": { - "direction": "up", - "value": 4 - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "p2body" - } - ], - "footer": { - "price": { - "type": "element", - "typeName": "BoldText", - "props": { - "variant": "text", - "value": "$14.00", - "subtextVariant": "text", - "size": "sm" - }, - "partial": false, - "hasDynamicProps": false - }, - "button": { - "type": "element", - "typeName": "Button", - "props": { - "label": "View Details", - "action": { - "k": "Comp", - "name": "Action", - "args": [ - { - "k": "Arr", - "els": [ - { - "k": "Comp", - "name": "ToAssistant", - "args": [ - { - "k": "Str", - "v": "Show details for Widget Mini" - } - ] - } - ] - } - ] - }, - "variant": "secondary" - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "p2btn" - } - } - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "p2" - } - ], - "layout": "grid", - "responsive": true - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "productCards" - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 29, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "openui-example-6", - "schema": "openui", - "input": "Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Stack", - "props": { - "children": [ - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "Team Roster", - "description": "Click a cell to edit" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tableHeader" - }, - { - "type": "element", - "typeName": "EditableTable", - "props": { - "name": "roster", - "columns": [ - { - "type": "text", - "key": "name", - "header": "Name" - }, - { - "type": "select", - "key": "role", - "header": "Role", - "options": [ - { - "value": "eng", - "label": "Engineering" - }, - { - "value": "design", - "label": "Design" - } - ] - }, - { - "type": "date-single", - "key": "start", - "header": "Start Date" - } - ], - "data": [ - { - "id": "1", - "values": [ - "Alex Kim", - "eng", - "2024-01-15" - ] - }, - { - "id": "2", - "values": [ - "Jamie Lee", - "design", - "2024-03-02" - ] - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "editTable" - }, - { - "type": "element", - "typeName": "InlineHeader", - "props": { - "heading": "Preferences", - "description": "Tell us how you like to work" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "formHeader" - }, - { - "type": "element", - "typeName": "Form", - "props": { - "name": "prefs", - "buttons": { - "type": "element", - "typeName": "Buttons", - "props": { - "buttons": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Save", - "action": { - "k": "Comp", - "name": "Action", - "args": [ - { - "k": "Arr", - "els": [ - { - "k": "Comp", - "name": "ToAssistant", - "args": [ - { - "k": "Str", - "v": "Save preferences" - } - ] - } - ] - } - ] - }, - "variant": "primary" - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "formButtons" - }, - "fields": [ - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Working Style", - "input": { - "type": "element", - "typeName": "OptionCards", - "props": { - "name": "style", - "type": "single", - "items": [ - { - "type": "element", - "typeName": "OptionCard", - "props": { - "value": "focused", - "title": "Deep Focus", - "subtitle": "Long uninterrupted blocks", - "topContent": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "target", - "category": "tools" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "style1icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "style1" - }, - { - "type": "element", - "typeName": "OptionCard", - "props": { - "value": "collab", - "title": "Collaborative", - "subtitle": "Frequent pairing and syncs", - "topContent": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "users", - "category": "people" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "style2icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "style2" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "styleCards" - }, - "hint": "Pick the one that fits best" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fc1" - }, - { - "type": "element", - "typeName": "FormControl", - "props": { - "label": "Tools", - "input": { - "type": "element", - "typeName": "Chips", - "props": { - "name": "tools", - "type": "multiple", - "items": [ - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "figma", - "label": "Figma", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "figma", - "category": "design" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tool1icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tool1" - }, - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "slack", - "label": "Slack", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "message-square", - "category": "communication" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tool2icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tool2" - }, - { - "type": "element", - "typeName": "ChipItem", - "props": { - "value": "notion", - "label": "Notion", - "icon": { - "type": "element", - "typeName": "Icon", - "props": { - "name": "notebook", - "category": "text" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tool3icon" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "tool3" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "toolChips" - }, - "hint": "Select all that apply" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "fc2" - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "prefsForm" - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 27, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "basic", - "schema": "test", - "input": "root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "Hi" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Go" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "b1" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 3, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "missing-required", - "schema": "test", - "input": "root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Go" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "b1" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 3, - "errors": [ - { - "code": "missing-required", - "component": "Text", - "path": "/text", - "message": "missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")", - "statementId": "t1" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "null-required-with-default", - "schema": "test", - "input": "root = Card([t1])\nt1 = Text(null)", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [ - { - "code": "null-required", - "component": "Text", - "path": "/text", - "message": "required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")", - "statementId": "t1" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "required-default-fills", - "schema": "test", - "input": "root = Card([x])\nx = Tagged(1, true, \"x\", null)", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Tagged", - "props": { - "count": 1, - "flag": true, - "kind": "x", - "tone": "neutral" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "x" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "unknown-component", - "schema": "test", - "input": "root = Card([Mystery(\"a\"), Text(\"b\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "b" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [ - { - "code": "unknown-component", - "component": "Mystery", - "path": "", - "message": "Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged", - "statementId": "root" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "excess-args", - "schema": "test", - "input": "root = Card([Text(\"a\", \"m\", \"extra\", 4)])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "a", - "size": "m" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [ - { - "code": "excess-args", - "component": "Text", - "path": "", - "message": "Text takes 2 arg(s), got 4 (2 excess dropped)", - "statementId": "root" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "type-mismatch-scalar", - "schema": "test", - "input": "root = Card([Text(42)], 7)", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [ - { - "code": "type-mismatch", - "component": "Text", - "path": "/text", - "message": "field \"/text\" expects string but got number", - "statementId": "root" - }, - { - "code": "type-mismatch", - "component": "Card", - "path": "/title", - "message": "field \"/title\" expects string but got number", - "statementId": "root" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "enum-mismatch", - "schema": "test", - "input": "root = Card([Text(\"a\", \"xl\"), Button(\"b\", null, \"tertiary\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "a", - "size": "m" - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "b", - "action": null - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [ - { - "code": "type-mismatch", - "component": "Text", - "path": "/size", - "message": "field \"/size\" expects one of [\"s\", \"m\", \"l\"] but got \"xl\"", - "statementId": "root" - }, - { - "code": "type-mismatch", - "component": "Button", - "path": "/variant", - "message": "field \"/variant\" expects one of [\"primary\", \"secondary\"] but got \"tertiary\"", - "statementId": "root" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "enum-partial-deferred", - "schema": "test", - "input": "root = Card([Text(\"a\", \"x", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "a", - "size": "x" - }, - "partial": true, - "hasDynamicProps": false - } - ] - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": true, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "integer-boolean-const", - "schema": "test", - "input": "root = Card([x])\nx = Tagged(1.5, \"yes\", \"y\", \"loud\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Tagged", - "props": { - "count": 1.5, - "tone": "loud" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "x" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [ - { - "code": "type-mismatch", - "component": "Tagged", - "path": "/flag", - "message": "field \"/flag\" expects boolean but got string", - "statementId": "x" - }, - { - "code": "type-mismatch", - "component": "Tagged", - "path": "/kind", - "message": "field \"/kind\" expects one of [\"x\"] but got \"y\"", - "statementId": "x" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "nested-object", - "schema": "test", - "input": "root = Card([c1, c2, c3])\nc1 = Chart([\"a\"], [1], {unit: \"kg\"})\nc2 = Chart([\"a\"], [1], {scale: 2})\nc3 = Chart([\"a\"], [1], {unit: 5, scale: \"big\"})", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Chart", - "props": { - "labels": [ - "a" - ], - "values": [ - 1 - ], - "meta": { - "unit": "kg" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "c1" - }, - { - "type": "element", - "typeName": "Chart", - "props": { - "labels": [ - "a" - ], - "values": [ - 1 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "c2" - }, - { - "type": "element", - "typeName": "Chart", - "props": { - "labels": [ - "a" - ], - "values": [ - 1 - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "c3" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 4, - "errors": [ - { - "code": "missing-required", - "component": "Chart", - "path": "/meta/unit", - "message": "missing required field \"/meta/unit\"", - "statementId": "c2" - }, - { - "code": "type-mismatch", - "component": "Chart", - "path": "/meta/unit", - "message": "field \"/meta/unit\" expects string but got number", - "statementId": "c3" - }, - { - "code": "type-mismatch", - "component": "Chart", - "path": "/meta/scale", - "message": "field \"/meta/scale\" expects number but got string", - "statementId": "c3" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "array-items-pruned", - "schema": "test", - "input": "root = Card([Chart([\"a\", 2, \"c\"], [1, \"x\", 3])])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Chart", - "props": { - "labels": [ - "a", - "c" - ], - "values": [ - 1, - 3 - ] - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [ - { - "code": "type-mismatch", - "component": "Chart", - "path": "/labels/1", - "message": "field \"/labels/1\" expects string but got number", - "statementId": "root" - }, - { - "code": "type-mismatch", - "component": "Chart", - "path": "/values/1", - "message": "field \"/values/1\" expects number but got string", - "statementId": "root" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "element-in-data-slot", - "schema": "test", - "input": "root = Card([Chart([Text(\"a\")], [1])])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Chart", - "props": { - "labels": [], - "values": [ - 1 - ] - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [ - { - "code": "type-mismatch", - "component": "Chart", - "path": "/labels/0", - "message": "field \"/labels/0\" expects string but got component \"Text\"", - "statementId": "root" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "unresolved-and-orphaned", - "schema": "test", - "input": "root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "x" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "a" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [ - "missing" - ], - "orphaned": [ - "lonely" - ], - "statementCount": 3, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "cycle", - "schema": "test", - "input": "root = Card([a])\na = Card([b])\nb = Card([a])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Card", - "props": { - "children": [] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "b" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "a" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [ - "a" - ], - "orphaned": [], - "statementCount": 3, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "self-reference", - "schema": "test", - "input": "root = Card([root])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Card", - "props": { - "children": [] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [ - "root" - ], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "no-root-first-component", - "schema": "test", - "input": "x = 1\nmain = Card([Text(\"a\")])\nother = Card([])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "a" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "main" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [ - "x", - "other" - ], - "statementCount": 3, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "root-name-statement", - "schema": "test", - "input": "Card = Card([Text(\"named\")])\nother = Card([])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "named" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "Card" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [ - "other" - ], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "duplicate-ids", - "schema": "test", - "input": "root = Card([a])\na = Text(\"first\")\na = Text(\"second\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "second" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "a" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "only-prose", - "schema": "test", - "input": "Here is your UI, it will appear below.", - "expected": { - "root": null, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 0, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "empty", - "schema": "test", - "input": "", - "expected": { - "root": null, - "meta": { - "incomplete": true, - "unresolved": [], - "orphaned": [], - "statementCount": 0, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "whitespace", - "schema": "test", - "input": " \n\t \n", - "expected": { - "root": null, - "meta": { - "incomplete": true, - "unresolved": [], - "orphaned": [], - "statementCount": 0, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "fences-and-prose", - "schema": "test", - "input": "Sure! Here it is:\n```openui\nroot = Card([a])\na = Text(\"fenced\")\n```\nAnything else?", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "fenced" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "a" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "multiple-fences", - "schema": "test", - "input": "```\nroot = Card([a])\n```\nand\n```\na = Text(\"second block\")\n```", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "second block" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "a" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "unclosed-fence", - "schema": "test", - "input": "```openui\nroot = Card([a])\na = Text(\"str", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "str" - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "a" - } - ] - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": true, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "fence-in-string", - "schema": "test", - "input": "root = Card([a])\na = Text(\"use ``` to fence\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "use ``` to fence" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "a" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "comments", - "schema": "test", - "input": "root = Card([a]) // trailing\n# full line\na = Text(\"not // a comment # here\")\n// done", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "not // a comment # here" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "a" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "crlf", - "schema": "test", - "input": "root = Card([a])\r\na = Text(\"windows\")\r\n", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "windows" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "a" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "string-escapes", - "schema": "test", - "input": "root = Card([a, b, c, d])\na = Text(\"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83d\\ude00\")\nb = Text('single \\' quote \\n esc \\q')\nc = Text(\"bad \\x escape\")\nd = Text(\"emoji 😀 and é and 漢字\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "tab\tnew\nquote\" back\\ unié pair😀" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "a" - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": "single ' quote \n esc q" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "b" - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": "bad \\x escape" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "c" - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": "emoji 😀 and é and 漢字" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "d" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 5, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "emoji-outside-strings", - "schema": "test", - "input": "root = Card([a]) 😀\na = Text(\"ok\") ✅", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "ok" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "a" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "unterminated-string", - "schema": "test", - "input": "root = Card([a])\na = Text(\"streaming tex", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "streaming tex" - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "a" - } - ] - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": true, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "unterminated-escape", - "schema": "test", - "input": "root = Card([a])\na = Text(\"ends with \\", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "ends with \\" - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "a" - } - ] - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": true, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "numbers", - "schema": "test", - "input": "root = Card([Chart([\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"], [-3, 1.5, 1e3, 007, -0, 2.5e-3])])\n$x = 1e\n$y = 1E+2\n$z = 3.", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Chart", - "props": { - "labels": [ - "a", - "b", - "c", - "d", - "e", - "f" - ], - "values": [ - -3, - 1.5, - 1000, - 7, - 0, - 0.0025 - ] - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 4, - "errors": [] - }, - "stateDeclarations": { - "$x": null, - "$y": 100, - "$z": { - "k": "Member", - "obj": { - "k": "Num", - "v": 3 - }, - "field": "?" - } - }, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "operators", - "schema": "test", - "input": "$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": { - "k": "Ternary", - "cond": { - "k": "BinOp", - "op": "||", - "left": { - "k": "BinOp", - "op": "&&", - "left": { - "k": "BinOp", - "op": ">", - "left": { - "k": "BinOp", - "op": "-", - "left": { - "k": "BinOp", - "op": "+", - "left": { - "k": "StateRef", - "n": "$a" - }, - "right": { - "k": "BinOp", - "op": "*", - "left": { - "k": "StateRef", - "n": "$b" - }, - "right": { - "k": "Num", - "v": 2 - } - } - }, - "right": { - "k": "Num", - "v": -1 - } - }, - "right": { - "k": "Num", - "v": 3 - } - }, - "right": { - "k": "UnaryOp", - "op": "!", - "operand": { - "k": "StateRef", - "n": "$c" - } - } - }, - "right": { - "k": "BinOp", - "op": "==", - "left": { - "k": "StateRef", - "n": "$a" - }, - "right": { - "k": "Str", - "v": "1" - } - } - }, - "then": { - "k": "Str", - "v": "yes" - }, - "else": { - "k": "Str", - "v": "no" - } - } - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 3, - "errors": [] - }, - "stateDeclarations": { - "$a": 1, - "$b": "2", - "$c": null - }, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "multiline-ternary", - "schema": "test", - "input": "$on = true\nroot = Card([t])\nt = Text($on\n ? \"enabled\"\n : \"disabled\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": { - "k": "Ternary", - "cond": { - "k": "StateRef", - "n": "$on" - }, - "then": { - "k": "Str", - "v": "enabled" - }, - "else": { - "k": "Str", - "v": "disabled" - } - } - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "t" - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 3, - "errors": [] - }, - "stateDeclarations": { - "$on": true - }, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "member-index", - "schema": "test", - "input": "$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": { - "k": "Member", - "obj": { - "k": "Index", - "obj": { - "k": "Member", - "obj": { - "k": "StateRef", - "n": "$data" - }, - "field": "rows" - }, - "index": { - "k": "Num", - "v": 1 - } - }, - "field": "name" - } - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": { - "k": "Member", - "obj": { - "k": "Member", - "obj": { - "k": "StateRef", - "n": "$data" - }, - "field": "rows" - }, - "field": "name" - } - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": { - "k": "Index", - "obj": { - "k": "StateRef", - "n": "$data" - }, - "index": { - "k": "Str", - "v": "key x" - } - } - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": { - "$data": { - "rows": [ - { - "name": "a" - }, - { - "name": "b" - } - ], - "key x": 1 - } - }, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "builtins", - "schema": "test", - "input": "$items = [3, 1, 2]\nroot = Card([Text(\"\" + @Count($items)), Text(\"\" + @Sum($items)), Text(@Round(2.555, 2) + \"\")])\nbare = Count($items)", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": { - "k": "BinOp", - "op": "+", - "left": { - "k": "Str", - "v": "" - }, - "right": { - "k": "Comp", - "name": "Count", - "args": [ - { - "k": "StateRef", - "n": "$items" - } - ] - } - } - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": { - "k": "BinOp", - "op": "+", - "left": { - "k": "Str", - "v": "" - }, - "right": { - "k": "Comp", - "name": "Sum", - "args": [ - { - "k": "StateRef", - "n": "$items" - } - ] - } - } - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": { - "k": "BinOp", - "op": "+", - "left": { - "k": "Comp", - "name": "Round", - "args": [ - { - "k": "Num", - "v": 2.555 - }, - { - "k": "Num", - "v": 2 - } - ] - }, - "right": { - "k": "Str", - "v": "" - } - } - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [ - "bare" - ], - "statementCount": 3, - "errors": [] - }, - "stateDeclarations": { - "$items": [ - 3, - 1, - 2 - ] - }, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "actions", - "schema": "test", - "input": "$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Inc", - "action": { - "k": "Comp", - "name": "Action", - "args": [ - { - "k": "Arr", - "els": [ - { - "k": "Comp", - "name": "Set", - "args": [ - { - "k": "StateRef", - "n": "$n" - }, - { - "k": "BinOp", - "op": "+", - "left": { - "k": "StateRef", - "n": "$n" - }, - "right": { - "k": "Num", - "v": 1 - } - } - ] - }, - { - "k": "Comp", - "name": "ToAssistant", - "args": [ - { - "k": "Str", - "v": "Bumped" - }, - { - "k": "Str", - "v": "ctx" - } - ] - } - ] - } - ] - } - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "b1" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Reset", - "action": { - "k": "Comp", - "name": "Action", - "args": [ - { - "k": "Arr", - "els": [ - { - "k": "Comp", - "name": "Reset", - "args": [ - { - "k": "StateRef", - "n": "$n" - } - ] - } - ] - } - ] - } - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "b2" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Docs", - "action": { - "k": "Comp", - "name": "Action", - "args": [ - { - "k": "Arr", - "els": [ - { - "k": "Comp", - "name": "OpenUrl", - "args": [ - { - "k": "Str", - "v": "https://openui.com" - } - ] - } - ] - } - ] - } - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "b3" - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 5, - "errors": [] - }, - "stateDeclarations": { - "$n": 0 - }, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "each", - "schema": "test", - "input": "$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": { - "k": "Comp", - "name": "Each", - "args": [ - { - "k": "StateRef", - "n": "$todos" - }, - { - "k": "Ref", - "n": "todo" - }, - { - "k": "Comp", - "name": "Text", - "args": [ - { - "k": "Member", - "obj": { - "k": "Ref", - "n": "todo" - }, - "field": "title" - } - ], - "mappedProps": { - "text": { - "k": "Member", - "obj": { - "k": "Ref", - "n": "todo" - }, - "field": "title" - } - } - } - ] - } - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": { - "$todos": [ - { - "title": "a", - "done": false - }, - { - "title": "b", - "done": true - } - ] - }, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "query-mutation", - "schema": "test", - "input": "$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": { - "k": "BinOp", - "op": "+", - "left": { - "k": "Member", - "obj": { - "k": "Member", - "obj": { - "k": "RuntimeRef", - "n": "users", - "refType": "query" - }, - "field": "rows" - }, - "field": "length" - }, - "right": { - "k": "Str", - "v": " users" - } - } - }, - "partial": false, - "hasDynamicProps": true - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Save", - "action": { - "k": "Comp", - "name": "Action", - "args": [ - { - "k": "Arr", - "els": [ - { - "k": "Comp", - "name": "Run", - "args": [ - { - "k": "RuntimeRef", - "n": "save", - "refType": "mutation" - } - ] - }, - { - "k": "Comp", - "name": "Run", - "args": [ - { - "k": "RuntimeRef", - "n": "users", - "refType": "query" - } - ] - } - ] - } - ] - } - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 4, - "errors": [] - }, - "stateDeclarations": { - "$q": "x", - "$page": null - }, - "queryStatements": [ - { - "statementId": "users", - "toolAST": { - "k": "Str", - "v": "list_users" - }, - "argsAST": { - "k": "Obj", - "entries": [ - [ - "search", - { - "k": "StateRef", - "n": "$q" - } - ], - [ - "page", - { - "k": "StateRef", - "n": "$page" - } - ] - ] - }, - "defaultsAST": { - "k": "Obj", - "entries": [ - [ - "rows", - { - "k": "Arr", - "els": [] - } - ] - ] - }, - "refreshAST": { - "k": "Num", - "v": 30 - }, - "deps": [ - "$q", - "$page" - ], - "complete": true - } - ], - "mutationStatements": [ - { - "statementId": "save", - "toolAST": { - "k": "Str", - "v": "save_user" - }, - "argsAST": { - "k": "Obj", - "entries": [ - [ - "name", - { - "k": "StateRef", - "n": "$q" - } - ] - ] - } - } - ] - } - }, - { - "name": "state-query", - "schema": "test", - "input": "$data = Query(\"get\", {})\nroot = Card([Text(\"x\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "x" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [ - { - "statementId": "$data", - "toolAST": { - "k": "Str", - "v": "get" - }, - "argsAST": { - "k": "Obj", - "entries": [] - }, - "defaultsAST": null, - "refreshAST": null, - "complete": true - } - ], - "mutationStatements": [] - } - }, - { - "name": "inline-query", - "schema": "test", - "input": "root = Card([Text(Query(\"get\", {}))])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [ - { - "code": "inline-reserved", - "component": "Query", - "path": "", - "message": "Query() must be declared as a top-level statement, not used inline as a value", - "statementId": "root" - }, - { - "code": "null-required", - "component": "Text", - "path": "/text", - "message": "required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")", - "statementId": "root" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "assignment", - "schema": "test", - "input": "$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Input", - "props": { - "name": "name", - "value": { - "k": "Assign", - "target": "$v", - "value": { - "k": "StateRef", - "n": "$value" - } - } - }, - "partial": false, - "hasDynamicProps": true - } - ] - }, - "partial": false, - "hasDynamicProps": true, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": { - "$v": "", - "$value": null - }, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "object-key-order", - "schema": "test", - "input": "$o = {b: 1, 2: \"two\", a: 3, 1: \"one\", \"10\": 10}\nroot = Card([Text(\"x\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "x" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": { - "$o": { - "1": "one", - "2": "two", - "10": 10, - "b": 1, - "a": 3 - } - }, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "missing-commas", - "schema": "test", - "input": "root = Card([Text(\"a\") Text(\"b\"), Text(\"c\"),])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "a" - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": "b" - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": "c" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "lowercase-builtin-name", - "schema": "test", - "input": "root = Card([Text(@first([1]))])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [ - { - "code": "unknown-component", - "component": "first", - "path": "", - "message": "Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged", - "statementId": "root" - }, - { - "code": "null-required", - "component": "Text", - "path": "/text", - "message": "required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")", - "statementId": "root" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "unknown-tokens", - "schema": "test", - "input": "root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "a" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "combining-characters", - "schema": "test", - "input": "root = Card([Text(\"e\\u0301 cafe\\u0301\"), Text(\"한국어\"), Text(\"ok\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "é café" - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": "한국어" - }, - "partial": false, - "hasDynamicProps": false - }, - { - "type": "element", - "typeName": "Text", - "props": { - "text": "ok" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "truncated-mid-call", - "schema": "test", - "input": "root = Card([a, b])\na = Text(\"one\")\nb = Button(\"tw", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "one" - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "a" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "tw" - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "b" - } - ] - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": true, - "unresolved": [], - "orphaned": [], - "statementCount": 3, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "truncated-mid-object", - "schema": "test", - "input": "root = Card([Chart([\"a\"], [1], {unit: \"k", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Chart", - "props": { - "labels": [ - "a" - ], - "values": [ - 1 - ], - "meta": { - "unit": "k" - } - }, - "partial": true, - "hasDynamicProps": false - } - ] - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": true, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "data-in-component-slot", - "schema": "test", - "input": "root = Card([Text(\"hi\"), { text: \"a\" }, \"b\", 3, [Text(\"x\")], true])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "hi" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [ - { - "code": "type-mismatch", - "component": "Card", - "path": "/children/1", - "message": "field \"/children/1\" expects Text | Button | Chart but got plain object", - "statementId": "root" - }, - { - "code": "type-mismatch", - "component": "Card", - "path": "/children/2", - "message": "field \"/children/2\" expects Text | Button | Chart but got string", - "statementId": "root" - }, - { - "code": "type-mismatch", - "component": "Card", - "path": "/children/3", - "message": "field \"/children/3\" expects Text | Button | Chart but got number", - "statementId": "root" - }, - { - "code": "type-mismatch", - "component": "Card", - "path": "/children/4", - "message": "field \"/children/4\" expects Text | Button | Chart but got array", - "statementId": "root" - }, - { - "code": "type-mismatch", - "component": "Card", - "path": "/children/5", - "message": "field \"/children/5\" expects Text | Button | Chart but got boolean", - "statementId": "root" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "data-in-component-slot-via-ref", - "schema": "test", - "input": "root = Card(items)\nitems = [{ text: \"a\" }]", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [ - { - "code": "type-mismatch", - "component": "Card", - "path": "/children/0", - "message": "field \"/children/0\" expects Text | Button | Chart but got plain object", - "statementId": "root" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "hoisted-data-def", - "schema": "hoisted", - "input": "root = Tree({ label: \"a\" })", - "expected": { - "root": { - "type": "element", - "typeName": "Tree", - "props": { - "node": { - "label": "a" - } - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "name": "cloud-envelope", - "schema": "chat", - "input": "]]>openui:content?thesys=true\n```openui-lang\nroot = Card([h, t])\nh = CardHeader(\"Q3\", \"Revenue\")\nt = TextContent(\"Up 12%\")\n```\n]]>openui:end", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "CardHeader", - "props": { - "title": "Q3", - "subtitle": "Revenue" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "h" - }, - { - "type": "element", - "typeName": "TextContent", - "props": { - "text": "Up 12%" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 3, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - } +{"name":"chat-example-1","schema":"chat","input":"Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":false,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"springList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":false,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":false,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":false,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":false,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{"type":"continue_conversation","context":"Show me the best hotels in Paris"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn2"},{"type":"element","typeName":"Button","props":{"label":"Build a Paris Itinerary","action":{"type":"continue_conversation","context":"Build a 5-day Paris itinerary for me"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn3"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[{"title":"Paris Travel Guide 2025","sourceName":"Travel and Tour World","url":"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/"},{"title":"Best Things to Do in Paris 2026","sourceName":"Time Out Paris","url":"http://www.timeout.fr/paris/en/for-tourists"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"chat-example-2","schema":"chat","input":"Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":false,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":false,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":false,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":false,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Cost per Lead","right":"$48.20","rightVariant":"number"},{"left":"Top Channel","right":"Organic Search","rightVariant":"text"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Break Down by Channel","action":{"type":"continue_conversation","context":"Break down this month's revenue by acquisition channel"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnChannels"},{"type":"element","typeName":"Button","props":{"label":"Forecast Next Quarter","action":{"type":"continue_conversation","context":"Forecast revenue and active users for next quarter"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnForecast"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionButtons"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":74,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"chat-example-3","schema":"chat","input":"Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":false,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":false,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":{"type":"element","typeName":"Icon","props":{"name":"home","category":"home"},"partial":false,"hasDynamicProps":false,"statementId":"ch3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch3"},{"type":"element","typeName":"ChipItem","props":{"value":"camping","label":"Camping / Glamping","icon":{"type":"element","typeName":"Icon","props":{"name":"tent","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"ch4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch4"}],"rules":{},"defaultValue":["hotel"]},"partial":false,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fcStay"},{"type":"element","typeName":"FormControl","props":{"label":"Special Requests or Notes","input":{"type":"element","typeName":"TextArea","props":{"name":"special-requests","placeholder":"e.g. vegetarian meals, wheelchair access, honeymoon surprise...","rows":4},"partial":false,"hasDynamicProps":false,"statementId":"notesArea"},"hint":"Any dietary needs, accessibility requirements, or specific interests?"},"partial":false,"hasDynamicProps":false,"statementId":"fcNotes"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":50,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"chat-example-4","schema":"chat","input":"Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":false,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":false,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},{"title":"Sajan Re (Official Music Video)","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=COUSCnFazzc"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"chat-example-5","schema":"chat","input":"Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"},{"type":"element","typeName":"FollowUpItem","props":{"text":"Show me a JavaScript comparison"},"partial":false,"hasDynamicProps":false,"statementId":"fu2"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"openui-example-1","schema":"openui","input":"Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]","expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript","Go"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1,8.5,5.2]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995,2012,2009]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"openui-example-2","schema":"openui","input":"Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])","expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[{"type":"element","typeName":"Series","props":{"category":"Product A","values":[120,150,180]},"partial":false,"hasDynamicProps":false,"statementId":"s1"},{"type":"element","typeName":"Series","props":{"category":"Product B","values":[90,110,140]},"partial":false,"hasDynamicProps":false,"statementId":"s2"}],"variant":"grouped"},"partial":false,"hasDynamicProps":false,"statementId":"chart"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"openui-example-3","schema":"openui","input":"Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])","expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Form","props":{"name":"contact","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Submit","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Submit"}]}]}]},"variant":"primary"},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Cancel","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Cancel"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"btns"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Name","input":{"type":"element","typeName":"Input","props":{"name":"name","placeholder":"Your name","type":"text","rules":{"required":true,"minLength":2}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"nameField"},{"type":"element","typeName":"FormControl","props":{"label":"Email","input":{"type":"element","typeName":"Input","props":{"name":"email","placeholder":"you@example.com","type":"email","rules":{"required":true,"email":true}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"emailField"},{"type":"element","typeName":"FormControl","props":{"label":"Country","input":{"type":"element","typeName":"Select","props":{"name":"country","items":[{"type":"element","typeName":"SelectItem","props":{"value":"us","label":"United States"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"uk","label":"United Kingdom"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"de","label":"Germany"},"partial":false,"hasDynamicProps":false}],"placeholder":"Select...","rules":{"required":true}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"countryField"},{"type":"element","typeName":"FormControl","props":{"label":"Message","input":{"type":"element","typeName":"TextArea","props":{"name":"message","placeholder":"Tell us more...","rows":4,"rules":{"required":true,"minLength":10}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"msgField"}]},"partial":false,"hasDynamicProps":true,"statementId":"form"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"openui-example-4","schema":"openui","input":"Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]","expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[{"type":"element","typeName":"TextContent","props":{"text":"Vue is a progressive framework by Evan You."},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"success","title":"Tip","description":"Vue has a gentle learning curve."},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"openui-example-5","schema":"openui","input":"Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")","expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":false,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":false,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Pro"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":false,"hasDynamicProps":true,"statementId":"p1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-mini","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"box","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p2icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Mini","subtitle":"New arrival","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p2header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"980 units","subtext":"Sold this month","trend":{"direction":"up","value":4}},"partial":false,"hasDynamicProps":false,"statementId":"p2body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$14.00","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Mini"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true,"statementId":"p2btn"}}},"partial":false,"hasDynamicProps":true,"statementId":"p2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":29,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"openui-example-6","schema":"openui","input":"Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])","expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":false,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":false,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":false,"hasDynamicProps":false,"statementId":"formHeader"},{"type":"element","typeName":"Form","props":{"name":"prefs","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Save preferences"}]}]}]},"variant":"primary"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Working Style","input":{"type":"element","typeName":"OptionCards","props":{"name":"style","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"focused","title":"Deep Focus","subtitle":"Long uninterrupted blocks","topContent":{"type":"element","typeName":"Icon","props":{"name":"target","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"style1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"style1"},{"type":"element","typeName":"OptionCard","props":{"value":"collab","title":"Collaborative","subtitle":"Frequent pairing and syncs","topContent":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"style2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"style2"}]},"partial":false,"hasDynamicProps":false,"statementId":"styleCards"},"hint":"Pick the one that fits best"},"partial":false,"hasDynamicProps":false,"statementId":"fc1"},{"type":"element","typeName":"FormControl","props":{"label":"Tools","input":{"type":"element","typeName":"Chips","props":{"name":"tools","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"figma","label":"Figma","icon":{"type":"element","typeName":"Icon","props":{"name":"figma","category":"design"},"partial":false,"hasDynamicProps":false,"statementId":"tool1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool1"},{"type":"element","typeName":"ChipItem","props":{"value":"slack","label":"Slack","icon":{"type":"element","typeName":"Icon","props":{"name":"message-square","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"tool2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool2"},{"type":"element","typeName":"ChipItem","props":{"value":"notion","label":"Notion","icon":{"type":"element","typeName":"Icon","props":{"name":"notebook","category":"text"},"partial":false,"hasDynamicProps":false,"statementId":"tool3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool3"}]},"partial":false,"hasDynamicProps":false,"statementId":"toolChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fc2"}]},"partial":false,"hasDynamicProps":true,"statementId":"prefsForm"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"basic","schema":"test","input":"root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"missing-required","schema":"test","input":"root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"null-required-with-default","schema":"test","input":"root = Card([t1])\nt1 = Text(null)","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"required-default-fills","schema":"test","input":"root = Card([x])\nx = Tagged(1, true, \"x\", null)","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"unknown-component","schema":"test","input":"root = Card([Mystery(\"a\"), Text(\"b\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"excess-args","schema":"test","input":"root = Card([Text(\"a\", \"m\", \"extra\", 4)])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"type-mismatch-scalar","schema":"test","input":"root = Card([Text(42)], 7)","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/title","message":"field \"/title\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"enum-mismatch","schema":"test","input":"root = Card([Text(\"a\", \"xl\"), Button(\"b\", null, \"tertiary\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/size","message":"field \"/size\" expects one of [\"s\", \"m\", \"l\"] but got \"xl\"","statementId":"root"},{"code":"type-mismatch","component":"Button","path":"/variant","message":"field \"/variant\" expects one of [\"primary\", \"secondary\"] but got \"tertiary\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"enum-partial-deferred","schema":"test","input":"root = Card([Text(\"a\", \"x","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"integer-boolean-const","schema":"test","input":"root = Card([x])\nx = Tagged(1.5, \"yes\", \"y\", \"loud\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"loud"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"},{"code":"type-mismatch","component":"Tagged","path":"/kind","message":"field \"/kind\" expects one of [\"x\"] but got \"y\"","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"nested-object","schema":"test","input":"root = Card([c1, c2, c3])\nc1 = Chart([\"a\"], [1], {unit: \"kg\"})\nc2 = Chart([\"a\"], [1], {scale: 2})\nc3 = Chart([\"a\"], [1], {unit: 5, scale: \"big\"})","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c3"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"},{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"array-items-pruned","schema":"test","input":"root = Card([Chart([\"a\", 2, \"c\"], [1, \"x\", 3])])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"element-in-data-slot","schema":"test","input":"root = Card([Chart([Text(\"a\")], [1])])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"unresolved-and-orphaned","schema":"test","input":"root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"cycle","schema":"test","input":"root = Card([a])\na = Card([b])\nb = Card([a])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"self-reference","schema":"test","input":"root = Card([root])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"no-root-first-component","schema":"test","input":"x = 1\nmain = Card([Text(\"a\")])\nother = Card([])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"root-name-statement","schema":"test","input":"Card = Card([Text(\"named\")])\nother = Card([])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"duplicate-ids","schema":"test","input":"root = Card([a])\na = Text(\"first\")\na = Text(\"second\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"only-prose","schema":"test","input":"Here is your UI, it will appear below.","expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"empty","schema":"test","input":"","expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"whitespace","schema":"test","input":" \n\t \n","expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"fences-and-prose","schema":"test","input":"Sure! Here it is:\n```openui\nroot = Card([a])\na = Text(\"fenced\")\n```\nAnything else?","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"multiple-fences","schema":"test","input":"```\nroot = Card([a])\n```\nand\n```\na = Text(\"second block\")\n```","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"unclosed-fence","schema":"test","input":"```openui\nroot = Card([a])\na = Text(\"str","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"str"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"fence-in-string","schema":"test","input":"root = Card([a])\na = Text(\"use ``` to fence\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"comments","schema":"test","input":"root = Card([a]) // trailing\n# full line\na = Text(\"not // a comment # here\")\n// done","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"crlf","schema":"test","input":"root = Card([a])\r\na = Text(\"windows\")\r\n","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"string-escapes","schema":"test","input":"root = Card([a, b, c, d])\na = Text(\"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83d\\ude00\")\nb = Text('single \\' quote \\n esc \\q')\nc = Text(\"bad \\x escape\")\nd = Text(\"emoji 😀 and é and 漢字\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and é and 漢字"},"partial":false,"hasDynamicProps":false,"statementId":"d"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"emoji-outside-strings","schema":"test","input":"root = Card([a]) 😀\na = Text(\"ok\") ✅","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"unterminated-string","schema":"test","input":"root = Card([a])\na = Text(\"streaming tex","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming tex"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"unterminated-escape","schema":"test","input":"root = Card([a])\na = Text(\"ends with \\","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with \\"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"numbers","schema":"test","input":"root = Card([Chart([\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"], [-3, 1.5, 1e3, 007, -0, 2.5e-3])])\n$x = 1e\n$y = 1E+2\n$z = 3.","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$x":null,"$y":100,"$z":{"k":"Member","obj":{"k":"Num","v":3},"field":"?"}},"queryStatements":[],"mutationStatements":[]}}, +{"name":"operators","schema":"test","input":"$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}}, +{"name":"multiline-ternary","schema":"test","input":"$on = true\nroot = Card([t])\nt = Text($on\n ? \"enabled\"\n : \"disabled\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabled"}}},"partial":false,"hasDynamicProps":true,"statementId":"t"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}}, +{"name":"member-index","schema":"test","input":"$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key x"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}}, +{"name":"builtins","schema":"test","input":"$items = [3, 1, 2]\nroot = Card([Text(\"\" + @Count($items)), Text(\"\" + @Sum($items)), Text(@Round(2.555, 2) + \"\")])\nbare = Count($items)","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}}, +{"name":"actions","schema":"test","input":"$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https://openui.com"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b3"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}}, +{"name":"each","schema":"test","input":"$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))","expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}}, +{"name":"query-mutation","schema":"test","input":"$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"users","refType":"query"}]}]}]}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}}, +{"name":"state-query","schema":"test","input":"$data = Query(\"get\", {})\nroot = Card([Text(\"x\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}}, +{"name":"inline-query","schema":"test","input":"root = Card([Text(Query(\"get\", {}))])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"assignment","schema":"test","input":"$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$value"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$value":null},"queryStatements":[],"mutationStatements":[]}}, +{"name":"object-key-order","schema":"test","input":"$o = {b: 1, 2: \"two\", a: 3, 1: \"one\", \"10\": 10}\nroot = Card([Text(\"x\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}}, +{"name":"missing-commas","schema":"test","input":"root = Card([Text(\"a\") Text(\"b\"), Text(\"c\"),])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"lowercase-builtin-name","schema":"test","input":"root = Card([Text(@first([1]))])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"unknown-tokens","schema":"test","input":"root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"combining-characters","schema":"test","input":"root = Card([Text(\"e\\u0301 cafe\\u0301\"), Text(\"한국어\"), Text(\"ok\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"truncated-mid-call","schema":"test","input":"root = Card([a, b])\na = Text(\"one\")\nb = Button(\"tw","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Button","props":{"label":"tw"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"truncated-mid-object","schema":"test","input":"root = Card([Chart([\"a\"], [1], {unit: \"k","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"k"}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"data-in-component-slot","schema":"test","input":"root = Card([Text(\"hi\"), { text: \"a\" }, \"b\", 3, [Text(\"x\")], true])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/5","message":"field \"/children/5\" expects Text | Button | Chart but got boolean","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"data-in-component-slot-via-ref","schema":"test","input":"root = Card(items)\nitems = [{ text: \"a\" }]","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"hoisted-data-def","schema":"hoisted","input":"root = Tree({ label: \"a\" })","expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":"a"}},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}, +{"name":"cloud-envelope","schema":"chat","input":"]]>openui:content?thesys=true\n```openui-lang\nroot = Card([h, t])\nh = CardHeader(\"Q3\", \"Revenue\")\nt = TextContent(\"Up 12%\")\n```\n]]>openui:end","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}} ] diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/prompts.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/prompts.json index e15109c3b4..000c4bcf60 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/prompts.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/prompts.json @@ -1,11171 +1,13 @@ [ - { - "name": "chat-default", - "spec": { - "root": "Card", - "components": { - "Card": { - "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", - "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." - }, - "CardHeader": { - "signature": "CardHeader(title?: string, subtitle?: string)", - "description": "Header with optional title and subtitle" - }, - "TextContent": { - "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "MarkDownRenderer": { - "signature": "MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")", - "description": "Renders markdown text with optional container variant" - }, - "Callout": { - "signature": "Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)", - "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." - }, - "TextCallout": { - "signature": "TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)", - "description": "Text callout with variant, title, and description" - }, - "Image": { - "signature": "Image(alt: string, src?: string)", - "description": "Image with alt text and optional URL" - }, - "ImageBlock": { - "signature": "ImageBlock(src: string, alt?: string)", - "description": "Image block with loading state" - }, - "ImageGallery": { - "signature": "ImageGallery(images: {src: string, alt?: string, details?: string}[])", - "description": "Gallery grid of images with modal preview" - }, - "CodeBlock": { - "signature": "CodeBlock(language: string, codeString: string)", - "description": "Syntax-highlighted code block" - }, - "Separator": { - "signature": "Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)", - "description": "Visual divider between content sections" - }, - "Table": { - "signature": "Table(columns: Col[])", - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", - "description": "Column definition — holds label + data array" - }, - "BarChart": { - "signature": "BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Vertical bars; use for comparing values across categories with one or more series" - }, - "LineChart": { - "signature": "LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Lines over categories; use for trends and continuous data over time" - }, - "AreaChart": { - "signature": "AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Filled area under lines; use for cumulative totals or volume trends over time" - }, - "RadarChart": { - "signature": "RadarChart(labels: string[], series: Series[])", - "description": "Spider/web chart; use for comparing multiple variables across one or more entities" - }, - "HorizontalBarChart": { - "signature": "HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)", - "description": "Horizontal bars; prefer when category labels are long or for ranked lists" - }, - "Series": { - "signature": "Series(category: string, values: number[])", - "description": "One data series" - }, - "PieChart": { - "signature": "PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")", - "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" - }, - "RadialChart": { - "signature": "RadialChart(labels: string[], values: number[])", - "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" - }, - "SingleStackedBarChart": { - "signature": "SingleStackedBarChart(labels: string[], values: number[])", - "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" - }, - "Slice": { - "signature": "Slice(category: string, value: number)", - "description": "One slice with label and numeric value" - }, - "ScatterChart": { - "signature": "ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)", - "description": "X/Y scatter plot; use for correlations, distributions, and clustering" - }, - "ScatterSeries": { - "signature": "ScatterSeries(name: string, points: Point[])", - "description": "Named dataset" - }, - "Point": { - "signature": "Point(x: number, y: number, z?: number)", - "description": "Data point with numeric coordinates" - }, - "Form": { - "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", - "description": "Form container with fields and explicit action buttons" - }, - "FormControl": { - "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", - "description": "Field with label, input component, and optional hint text" - }, - "Label": { - "signature": "Label(text: string)", - "description": "Text label" - }, - "Input": { - "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "TextArea": { - "signature": "TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Select": { - "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", - "description": "" - }, - "SelectItem": { - "signature": "SelectItem(value: string, label: string)", - "description": "Option for Select" - }, - "DatePicker": { - "signature": "DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Slider": { - "signature": "Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "Numeric slider input; supports continuous and discrete (stepped) variants" - }, - "CheckBoxGroup": { - "signature": "CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)", - "description": "" - }, - "CheckBoxItem": { - "signature": "CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)", - "description": "" - }, - "RadioGroup": { - "signature": "RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "RadioItem": { - "signature": "RadioItem(label: string, description: string, value: string)", - "description": "" - }, - "SwitchGroup": { - "signature": "SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)", - "description": "Group of switch toggles" - }, - "SwitchItem": { - "signature": "SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)", - "description": "Individual switch toggle" - }, - "Button": { - "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", - "description": "Clickable button" - }, - "Buttons": { - "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "ListBlock": { - "signature": "ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")", - "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." - }, - "ListItem": { - "signature": "ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)", - "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." - }, - "FollowUpBlock": { - "signature": "FollowUpBlock(items: FollowUpItem[])", - "description": "List of clickable follow-up suggestions placed at the end of a response" - }, - "FollowUpItem": { - "signature": "FollowUpItem(text: string)", - "description": "Clickable follow-up suggestion — when clicked, sends text as user message" - }, - "SectionBlock": { - "signature": "SectionBlock(sections: SectionItem[], isFoldable?: boolean)", - "description": "Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section." - }, - "SectionItem": { - "signature": "SectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[])", - "description": "Section with a label and collapsible content — used inside SectionBlock" - }, - "Tabs": { - "signature": "Tabs(items: TabItem[])", - "description": "Tabbed container" - }, - "TabItem": { - "signature": "TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[])", - "description": "value is unique id, trigger is tab label, content is array of components" - }, - "Accordion": { - "signature": "Accordion(items: AccordionItem[])", - "description": "Collapsible sections" - }, - "AccordionItem": { - "signature": "AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[])", - "description": "value is unique id, trigger is section title" - }, - "Steps": { - "signature": "Steps(items: StepsItem[])", - "description": "Step-by-step guide" - }, - "StepsItem": { - "signature": "StepsItem(title: string, details: string)", - "description": "title and details text for one step" - }, - "Carousel": { - "signature": "Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\")", - "description": "Horizontal scrollable carousel" - }, - "TagBlock": { - "signature": "TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")", - "description": "tags is an array of strings; optional size sm | md | lg" - }, - "Tag": { - "signature": "Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")", - "description": "Styled tag/badge with optional Icon and variant" - }, - "EntityList": { - "signature": "EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})", - "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." - }, - "InlineHeader": { - "signature": "InlineHeader(heading: string, description?: string)", - "description": "Compact section heading with an optional one-line description, for use inside cards." - }, - "Icon": { - "signature": "Icon(name: string, category?: string)", - "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." - }, - "IconButton": { - "signature": "IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")", - "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." - }, - "EditableTable": { - "signature": "EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])", - "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" - }, - "ChipItem": { - "signature": "ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)", - "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." - }, - "Chips": { - "signature": "Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", - "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." - }, - "OptionCard": { - "signature": "OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)", - "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." - }, - "OptionCards": { - "signature": "OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", - "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." - }, - "Text": { - "signature": "Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", - "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "BoldText": { - "signature": "BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", - "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "IconText": { - "signature": "IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")", - "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." - }, - "ImageText": { - "signature": "ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)", - "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." - }, - "ImageTextLarge": { - "signature": "ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)", - "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." - }, - "MetricIndicatorInline": { - "signature": "MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})", - "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." - }, - "MetricIndicatorWithStrikethrough": { - "signature": "MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})", - "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." - }, - "SnippetCardItem": { - "signature": "SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)", - "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." - }, - "SnippetCardBlock": { - "signature": "SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." - }, - "OverviewCardItem": { - "signature": "OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)", - "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." - }, - "OverviewCardBlock": { - "signature": "OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." - }, - "ContextCardItem": { - "signature": "ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)", - "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." - }, - "ContextCardBlock": { - "signature": "ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." - }, - "CompositeCardItem": { - "signature": "CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})", - "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." - }, - "CompositeCardBlock": { - "signature": "CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." - }, - "VisualCardItem": { - "signature": "VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)", - "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." - }, - "VisualCardBlock": { - "signature": "VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." - } - }, - "componentGroups": [ - { - "name": "Content", - "components": [ - "CardHeader", - "TextContent", - "MarkDownRenderer", - "Callout", - "TextCallout", - "Image", - "ImageBlock", - "ImageGallery", - "CodeBlock", - "Separator", - "InlineHeader" - ], - "notes": [ - "- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).", - "- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card." - ] - }, - { - "name": "Tables", - "components": [ - "Table", - "Col", - "EditableTable" - ], - "notes": [ - "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", - "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes." - ] - }, - { - "name": "Charts (2D)", - "components": [ - "BarChart", - "LineChart", - "AreaChart", - "RadarChart", - "HorizontalBarChart", - "Series" - ] - }, - { - "name": "Charts (1D)", - "components": [ - "PieChart", - "RadialChart", - "SingleStackedBarChart", - "Slice" - ] - }, - { - "name": "Charts (Scatter)", - "components": [ - "ScatterChart", - "ScatterSeries", - "Point" - ] - }, - { - "name": "Forms", - "components": [ - "Form", - "FormControl", - "Label", - "Input", - "TextArea", - "Select", - "SelectItem", - "DatePicker", - "Slider", - "CheckBoxGroup", - "CheckBoxItem", - "RadioGroup", - "RadioItem", - "SwitchGroup", - "SwitchItem", - "Chips", - "ChipItem", - "OptionCards", - "OptionCard" - ], - "notes": [ - "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", - "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", - "- Define EACH FormControl as its own reference — do NOT inline all controls in one array.", - "- NEVER nest Form inside Form.", - "- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).", - "- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }", - "- The renderer shows error messages automatically — do NOT generate error text in the UI" - ] - }, - { - "name": "Buttons", - "components": [ - "Button", - "Buttons", - "Icon", - "IconButton" - ], - "notes": [ - "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard." - ] - }, - { - "name": "Lists & Follow-ups", - "components": [ - "ListBlock", - "ListItem", - "FollowUpBlock", - "FollowUpItem" - ], - "notes": [ - "- Use ListBlock with ListItem references for numbered lists.", - "- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.", - "- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.", - "- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.", - "- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })" - ] - }, - { - "name": "Sections", - "components": [ - "SectionBlock", - "SectionItem" - ], - "notes": [ - "- SectionBlock renders collapsible accordion sections that auto-open as they stream.", - "- Each section needs a unique `value` id, a `trigger` label, and a `content` array.", - "- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])", - "- Set isFoldable=false to render sections as flat headers instead of accordion." - ] - }, - { - "name": "Layout", - "components": [ - "Tabs", - "TabItem", - "Accordion", - "AccordionItem", - "Steps", - "StepsItem", - "Carousel" - ], - "notes": [ - "- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.", - "- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])", - "- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.", - "- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.", - "- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs." - ] - }, - { - "name": "Data Display", - "components": [ - "TagBlock", - "Tag", - "EntityList" - ], - "notes": [ - "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not." - ] - }, - { - "name": "Cards", - "components": [ - "SnippetCardBlock", - "SnippetCardItem", - "OverviewCardBlock", - "OverviewCardItem", - "ContextCardBlock", - "ContextCardItem", - "CompositeCardBlock", - "CompositeCardItem", - "VisualCardBlock", - "VisualCardItem", - "Text", - "BoldText", - "IconText", - "ImageText", - "ImageTextLarge", - "MetricIndicatorInline", - "MetricIndicatorWithStrikethrough" - ], - "notes": [ - "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", - "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", - "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", - "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", - "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", - "- VisualCardItem: image-first card with a BoldText body and optional Tag.", - "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card." - ] - } - ] - }, - "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Content\nCardHeader(title?: string, subtitle?: string) — Header with optional title and subtitle\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nMarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\") — Renders markdown text with optional container variant\nCallout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding) — Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.\nTextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string) — Text callout with variant, title, and description\nImage(alt: string, src?: string) — Image with alt text and optional URL\nImageBlock(src: string, alt?: string) — Image block with loading state\nImageGallery(images: {src: string, alt?: string, details?: string}[]) — Gallery grid of images with modal preview\nCodeBlock(language: string, codeString: string) — Syntax-highlighted code block\nSeparator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean) — Visual divider between content sections\nInlineHeader(heading: string, description?: string) — Compact section heading with an optional one-line description, for use inside cards.\n- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).\n- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card.\n\n### Tables\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\nEditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[]) — Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field\n- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).\n- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.\n\n### Charts (2D)\nBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number) — Vertical bars; use for comparing values across categories with one or more series\nLineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Lines over categories; use for trends and continuous data over time\nAreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Filled area under lines; use for cumulative totals or volume trends over time\nRadarChart(labels: string[], series: Series[]) — Spider/web chart; use for comparing multiple variables across one or more entities\nHorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string) — Horizontal bars; prefer when category labels are long or for ranked lists\nSeries(category: string, values: number[]) — One data series\n\n### Charts (1D)\nPieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\") — Circular slices; use plucked arrays: PieChart(data.categories, data.values)\nRadialChart(labels: string[], values: number[]) — Radial bars; use plucked arrays: RadialChart(data.categories, data.values)\nSingleStackedBarChart(labels: string[], values: number[]) — Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)\nSlice(category: string, value: number) — One slice with label and numeric value\n\n### Charts (Scatter)\nScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string) — X/Y scatter plot; use for correlations, distributions, and clustering\nScatterSeries(name: string, points: Point[]) — Named dataset\nPoint(x: number, y: number, z?: number) — Data point with numeric coordinates\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nLabel(text: string) — Text label\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nTextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nDatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSlider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding) — Numeric slider input; supports continuous and discrete (stepped) variants\nCheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)\nCheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)\nRadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nRadioItem(label: string, description: string, value: string)\nSwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>) — Group of switch toggles\nSwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean) — Individual switch toggle\nChips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.\nChipItem(value: string, label: string, icon?: Icon, disabled?: boolean) — A single selectable chip inside a Chips group, with a value, label and optional icon.\nOptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.\nOptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean) — A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.\n- Chips: compact single/multiple selection pills. Use ChipItem references for each option.\n- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.\n- Define EACH FormControl as its own reference — do NOT inline all controls in one array.\n- NEVER nest Form inside Form.\n- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).\n- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }\n- The renderer shows error messages automatically — do NOT generate error text in the UI\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nIcon(name: string, category?: string) — A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.\nIconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\") — Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.\n- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.\n\n### Lists & Follow-ups\nListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\") — A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.\nListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression) — Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.\nFollowUpBlock(items: FollowUpItem[]) — List of clickable follow-up suggestions placed at the end of a response\nFollowUpItem(text: string) — Clickable follow-up suggestion — when clicked, sends text as user message\n- Use ListBlock with ListItem references for numbered lists.\n- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.\n- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.\n- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.\n- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })\n\n### Sections\nSectionBlock(sections: SectionItem[], isFoldable?: boolean) — Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section.\nSectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[]) — Section with a label and collapsible content — used inside SectionBlock\n- SectionBlock renders collapsible accordion sections that auto-open as they stream.\n- Each section needs a unique `value` id, a `trigger` label, and a `content` array.\n- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])\n- Set isFoldable=false to render sections as flat headers instead of accordion.\n\n### Layout\nTabs(items: TabItem[]) — Tabbed container\nTabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[]) — value is unique id, trigger is tab label, content is array of components\nAccordion(items: AccordionItem[]) — Collapsible sections\nAccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[]) — value is unique id, trigger is section title\nSteps(items: StepsItem[]) — Step-by-step guide\nStepsItem(title: string, details: string) — title and details text for one step\nCarousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\") — Horizontal scrollable carousel\n- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.\n- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])\n- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.\n- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.\n- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs.\n\n### Data Display\nTagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\") — tags is an array of strings; optional size sm | md | lg\nTag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\") — Styled tag/badge with optional Icon and variant\nEntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}) — Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.\n- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.\n\n### Cards\nSnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.\nSnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText) — One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).\nOverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.\nOverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline) — One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.\nContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.\nContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string) — A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.\nCompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.\nCompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button}) — A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.\nVisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.\nVisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string) — A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).\nText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nBoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nIconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\") — An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.\nImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number) — A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.\nImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean) — A full-width banner image above a bold title and optional subtitle. src must be a real image URL.\nMetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional +/- percentage trend and subtext, all on one line.\nMetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.\n- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.\n- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.\n- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.\n- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.\n- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.\n- VisualCardItem: image-first card with a BoldText body and optional Tag.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root." - }, - { - "name": "chat-options", - "spec": { - "root": "Card", - "components": { - "Card": { - "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", - "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." - }, - "CardHeader": { - "signature": "CardHeader(title?: string, subtitle?: string)", - "description": "Header with optional title and subtitle" - }, - "TextContent": { - "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "MarkDownRenderer": { - "signature": "MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")", - "description": "Renders markdown text with optional container variant" - }, - "Callout": { - "signature": "Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)", - "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." - }, - "TextCallout": { - "signature": "TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)", - "description": "Text callout with variant, title, and description" - }, - "Image": { - "signature": "Image(alt: string, src?: string)", - "description": "Image with alt text and optional URL" - }, - "ImageBlock": { - "signature": "ImageBlock(src: string, alt?: string)", - "description": "Image block with loading state" - }, - "ImageGallery": { - "signature": "ImageGallery(images: {src: string, alt?: string, details?: string}[])", - "description": "Gallery grid of images with modal preview" - }, - "CodeBlock": { - "signature": "CodeBlock(language: string, codeString: string)", - "description": "Syntax-highlighted code block" - }, - "Separator": { - "signature": "Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)", - "description": "Visual divider between content sections" - }, - "Table": { - "signature": "Table(columns: Col[])", - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", - "description": "Column definition — holds label + data array" - }, - "BarChart": { - "signature": "BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Vertical bars; use for comparing values across categories with one or more series" - }, - "LineChart": { - "signature": "LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Lines over categories; use for trends and continuous data over time" - }, - "AreaChart": { - "signature": "AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Filled area under lines; use for cumulative totals or volume trends over time" - }, - "RadarChart": { - "signature": "RadarChart(labels: string[], series: Series[])", - "description": "Spider/web chart; use for comparing multiple variables across one or more entities" - }, - "HorizontalBarChart": { - "signature": "HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)", - "description": "Horizontal bars; prefer when category labels are long or for ranked lists" - }, - "Series": { - "signature": "Series(category: string, values: number[])", - "description": "One data series" - }, - "PieChart": { - "signature": "PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")", - "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" - }, - "RadialChart": { - "signature": "RadialChart(labels: string[], values: number[])", - "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" - }, - "SingleStackedBarChart": { - "signature": "SingleStackedBarChart(labels: string[], values: number[])", - "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" - }, - "Slice": { - "signature": "Slice(category: string, value: number)", - "description": "One slice with label and numeric value" - }, - "ScatterChart": { - "signature": "ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)", - "description": "X/Y scatter plot; use for correlations, distributions, and clustering" - }, - "ScatterSeries": { - "signature": "ScatterSeries(name: string, points: Point[])", - "description": "Named dataset" - }, - "Point": { - "signature": "Point(x: number, y: number, z?: number)", - "description": "Data point with numeric coordinates" - }, - "Form": { - "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", - "description": "Form container with fields and explicit action buttons" - }, - "FormControl": { - "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", - "description": "Field with label, input component, and optional hint text" - }, - "Label": { - "signature": "Label(text: string)", - "description": "Text label" - }, - "Input": { - "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "TextArea": { - "signature": "TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Select": { - "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", - "description": "" - }, - "SelectItem": { - "signature": "SelectItem(value: string, label: string)", - "description": "Option for Select" - }, - "DatePicker": { - "signature": "DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Slider": { - "signature": "Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "Numeric slider input; supports continuous and discrete (stepped) variants" - }, - "CheckBoxGroup": { - "signature": "CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)", - "description": "" - }, - "CheckBoxItem": { - "signature": "CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)", - "description": "" - }, - "RadioGroup": { - "signature": "RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "RadioItem": { - "signature": "RadioItem(label: string, description: string, value: string)", - "description": "" - }, - "SwitchGroup": { - "signature": "SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)", - "description": "Group of switch toggles" - }, - "SwitchItem": { - "signature": "SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)", - "description": "Individual switch toggle" - }, - "Button": { - "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", - "description": "Clickable button" - }, - "Buttons": { - "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "ListBlock": { - "signature": "ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")", - "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." - }, - "ListItem": { - "signature": "ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)", - "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." - }, - "FollowUpBlock": { - "signature": "FollowUpBlock(items: FollowUpItem[])", - "description": "List of clickable follow-up suggestions placed at the end of a response" - }, - "FollowUpItem": { - "signature": "FollowUpItem(text: string)", - "description": "Clickable follow-up suggestion — when clicked, sends text as user message" - }, - "SectionBlock": { - "signature": "SectionBlock(sections: SectionItem[], isFoldable?: boolean)", - "description": "Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section." - }, - "SectionItem": { - "signature": "SectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[])", - "description": "Section with a label and collapsible content — used inside SectionBlock" - }, - "Tabs": { - "signature": "Tabs(items: TabItem[])", - "description": "Tabbed container" - }, - "TabItem": { - "signature": "TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[])", - "description": "value is unique id, trigger is tab label, content is array of components" - }, - "Accordion": { - "signature": "Accordion(items: AccordionItem[])", - "description": "Collapsible sections" - }, - "AccordionItem": { - "signature": "AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[])", - "description": "value is unique id, trigger is section title" - }, - "Steps": { - "signature": "Steps(items: StepsItem[])", - "description": "Step-by-step guide" - }, - "StepsItem": { - "signature": "StepsItem(title: string, details: string)", - "description": "title and details text for one step" - }, - "Carousel": { - "signature": "Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\")", - "description": "Horizontal scrollable carousel" - }, - "TagBlock": { - "signature": "TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")", - "description": "tags is an array of strings; optional size sm | md | lg" - }, - "Tag": { - "signature": "Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")", - "description": "Styled tag/badge with optional Icon and variant" - }, - "EntityList": { - "signature": "EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})", - "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." - }, - "InlineHeader": { - "signature": "InlineHeader(heading: string, description?: string)", - "description": "Compact section heading with an optional one-line description, for use inside cards." - }, - "Icon": { - "signature": "Icon(name: string, category?: string)", - "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." - }, - "IconButton": { - "signature": "IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")", - "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." - }, - "EditableTable": { - "signature": "EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])", - "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" - }, - "ChipItem": { - "signature": "ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)", - "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." - }, - "Chips": { - "signature": "Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", - "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." - }, - "OptionCard": { - "signature": "OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)", - "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." - }, - "OptionCards": { - "signature": "OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", - "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." - }, - "Text": { - "signature": "Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", - "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "BoldText": { - "signature": "BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", - "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "IconText": { - "signature": "IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")", - "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." - }, - "ImageText": { - "signature": "ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)", - "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." - }, - "ImageTextLarge": { - "signature": "ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)", - "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." - }, - "MetricIndicatorInline": { - "signature": "MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})", - "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." - }, - "MetricIndicatorWithStrikethrough": { - "signature": "MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})", - "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." - }, - "SnippetCardItem": { - "signature": "SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)", - "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." - }, - "SnippetCardBlock": { - "signature": "SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." - }, - "OverviewCardItem": { - "signature": "OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)", - "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." - }, - "OverviewCardBlock": { - "signature": "OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." - }, - "ContextCardItem": { - "signature": "ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)", - "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." - }, - "ContextCardBlock": { - "signature": "ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." - }, - "CompositeCardItem": { - "signature": "CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})", - "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." - }, - "CompositeCardBlock": { - "signature": "CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." - }, - "VisualCardItem": { - "signature": "VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)", - "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." - }, - "VisualCardBlock": { - "signature": "VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." - } - }, - "componentGroups": [ - { - "name": "Content", - "components": [ - "CardHeader", - "TextContent", - "MarkDownRenderer", - "Callout", - "TextCallout", - "Image", - "ImageBlock", - "ImageGallery", - "CodeBlock", - "Separator", - "InlineHeader" - ], - "notes": [ - "- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).", - "- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card." - ] - }, - { - "name": "Tables", - "components": [ - "Table", - "Col", - "EditableTable" - ], - "notes": [ - "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", - "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes." - ] - }, - { - "name": "Charts (2D)", - "components": [ - "BarChart", - "LineChart", - "AreaChart", - "RadarChart", - "HorizontalBarChart", - "Series" - ] - }, - { - "name": "Charts (1D)", - "components": [ - "PieChart", - "RadialChart", - "SingleStackedBarChart", - "Slice" - ] - }, - { - "name": "Charts (Scatter)", - "components": [ - "ScatterChart", - "ScatterSeries", - "Point" - ] - }, - { - "name": "Forms", - "components": [ - "Form", - "FormControl", - "Label", - "Input", - "TextArea", - "Select", - "SelectItem", - "DatePicker", - "Slider", - "CheckBoxGroup", - "CheckBoxItem", - "RadioGroup", - "RadioItem", - "SwitchGroup", - "SwitchItem", - "Chips", - "ChipItem", - "OptionCards", - "OptionCard" - ], - "notes": [ - "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", - "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", - "- Define EACH FormControl as its own reference — do NOT inline all controls in one array.", - "- NEVER nest Form inside Form.", - "- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).", - "- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }", - "- The renderer shows error messages automatically — do NOT generate error text in the UI" - ] - }, - { - "name": "Buttons", - "components": [ - "Button", - "Buttons", - "Icon", - "IconButton" - ], - "notes": [ - "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard." - ] - }, - { - "name": "Lists & Follow-ups", - "components": [ - "ListBlock", - "ListItem", - "FollowUpBlock", - "FollowUpItem" - ], - "notes": [ - "- Use ListBlock with ListItem references for numbered lists.", - "- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.", - "- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.", - "- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.", - "- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })" - ] - }, - { - "name": "Sections", - "components": [ - "SectionBlock", - "SectionItem" - ], - "notes": [ - "- SectionBlock renders collapsible accordion sections that auto-open as they stream.", - "- Each section needs a unique `value` id, a `trigger` label, and a `content` array.", - "- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])", - "- Set isFoldable=false to render sections as flat headers instead of accordion." - ] - }, - { - "name": "Layout", - "components": [ - "Tabs", - "TabItem", - "Accordion", - "AccordionItem", - "Steps", - "StepsItem", - "Carousel" - ], - "notes": [ - "- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.", - "- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])", - "- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.", - "- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.", - "- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs." - ] - }, - { - "name": "Data Display", - "components": [ - "TagBlock", - "Tag", - "EntityList" - ], - "notes": [ - "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not." - ] - }, - { - "name": "Cards", - "components": [ - "SnippetCardBlock", - "SnippetCardItem", - "OverviewCardBlock", - "OverviewCardItem", - "ContextCardBlock", - "ContextCardItem", - "CompositeCardBlock", - "CompositeCardItem", - "VisualCardBlock", - "VisualCardItem", - "Text", - "BoldText", - "IconText", - "ImageText", - "ImageTextLarge", - "MetricIndicatorInline", - "MetricIndicatorWithStrikethrough" - ], - "notes": [ - "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", - "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", - "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", - "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", - "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", - "- VisualCardItem: image-first card with a BoldText body and optional Tag.", - "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card." - ] - } - ], - "examples": [ - "Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }", - "Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")", - "Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)", - "Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }", - "Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")" - ], - "additionalRules": [ - "When asked about data, generate realistic/plausible data", - "Every response is a single Card(children) — children stack vertically automatically. No layout params are needed on Card.", - "Card is the only layout container. Do NOT use Stack. Use Tabs to switch between sections, Carousel for horizontal scroll.", - "Use FollowUpBlock at the END of a Card to suggest what the user can do or ask next.", - "Use ListBlock when presenting a set of options or steps; give each ListItem an action (5th argument) to make it clickable — without one the item is plain text.", - "Use SectionBlock to group long responses into collapsible sections — good for reports, FAQs, and structured content.", - "Use SectionItem inside SectionBlock: each item needs a unique value id, a trigger (header label), and a content array.", - "Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])", - "IMPORTANT: Every slide in a Carousel must use the same component structure in the same order — e.g. all slides: [title, image, description, tags].", - "For forms, define one FormControl reference per field so controls can stream progressively.", - "For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).", - "Never nest Form inside Form.", - "CardHeader is the page-level heading — place it as the first child of Card; InlineHeader is a lighter subsection label for a block inside the response, and is redundant when the following component already has a heading.", - "Never use Callout or TextCallout to justify why you did what you did or for any meta-information.", - "Every image slot (Image, ImageBlock, ImageGallery, VisualCardItem/ContextCardItem bgImageSrc, ImageText, ImageTextLarge, ListItem image) requires a REAL URL from a tool result, the conversation, or the user — NEVER invent, guess, or template a URL.", - "If no image URL is in context, compose without image components — icons, gray ContextCardItems, and charts still make rich layouts.", - "Argument-order trap: Image takes alt FIRST, while ImageBlock, ImageText, and ImageTextLarge take src FIRST — alt text in a src slot ships a broken image.", - "Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items, all with the same structure; use layout \"grid\" for primary side-by-side comparison and \"carousel\" for secondary browsing.", - "The card-block action is BLOCK-LEVEL: one action shared by every card, with the clicked card's details attached automatically — keep continue_conversation context generic (e.g. \"Tell me more about this destination\"), and never use a block-level open_url since it would send every card to the same URL.", - "Card items have NO per-item action: to give each item its own external link, use CompositeCardItem with footer { button: Button(label, { type: \"open_url\", url }) } — never claim a card opens a link it cannot.", - "Text, BoldText, IconText, ImageText, ImageTextLarge and MetricIndicator* are inline building blocks used INSIDE card items — do not place them directly in the root Card.", - "EntityList size \"small\" is reserved for CompositeCardItem body content (no header/footer); use size \"default\" elsewhere.", - "Tag variant must be semantically correct (success=positive, danger=negative, warning=cautionary, info=informational, neutral=label); Tag takes an optional Icon second, so use Tag(text, icon, size, variant) when a variant is needed.", - "TagBlock takes plain strings — keep it to at most 3 tags.", - "ListBlock variant \"number\" is for ordered sequences and rankings, \"image\" for products/profiles with a real image; Steps is for ordered sequential processes only.", - "Use SectionBlock to divide a long response into independent, equally prominent topics; use Tabs when the items are alternative views of the same thing; set isFoldable=false unless a section has 4+ distinct blocks; never make SectionBlock the first Card child.", - "Accordion is for supplementary or FAQ content only — never primary information, 3-5 items max, and always the last component in its section or card.", - "Charts: LineChart/AreaChart variant \"natural\" for smooth trends and \"linear\" for precise point-to-point data; BarChart \"grouped\" for side-by-side comparison and \"stacked\" for part-to-whole; prefer HorizontalBarChart when category labels are long or numerous.", - "For large chart values, scale the data and put the unit in the axis label (e.g. yLabel \"Revenue ($k)\") instead of passing raw thousands or millions.", - "Quantitative asks get a chart (plus KPI cards where useful) in the FIRST response — do not answer numbers with prose or a table alone.", - "Table is column-oriented: each Col holds its own data array of plain strings or numbers (never components), and every column's array must have the same length.", - "Use EditableTable ONLY when the user or app explicitly asks for an editable table; default to Table for read-only data.", - "Every Form MUST have EXACTLY ONE submit Button with variant \"primary\" — that button validates the form; other buttons (secondary/tertiary escape hatches like \"Just Surprise Me\") skip validation, and there is never a reset button.", - "Prefer structured inputs (Select, Chips, OptionCards, DatePicker, Slider) over free-text Input, give every FormControl a clear label (and a hint where it prevents mistakes), and keep each field name unique within the response.", - "Validation rules ({ required: true, email: true, minLength: 8, ... }) are enforced with inline errors — use them for genuinely essential fields, but never require a free-text field where leaving it blank is meaningful.", - "Form inputs work ONLY inside a FormControl within a Form; for tappable suggestion choices OUTSIDE a form, use Buttons of continue_conversation Buttons — never a bare OptionCards or Chips.", - "Only add Buttons for real actions: form submit, open_url with a URL from a tool or the user (never fabricated), or a continue_conversation follow-up — never a button for an app action (open, download, export, edit) you cannot perform.", - "Every Button label must accurately describe what clicking it does; use \"primary\" for the main action and \"secondary\"/\"tertiary\" only for lower-emphasis supporting actions.", - "Icon: always include the category argument — it enables fallback matching when the exact lucide name is unavailable.", - "Pass sources on Card ONLY when the answer relies on real references you actually have, and cite them inline in TextContent as [1], [2] (1-based index into sources)." - ] - }, - "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Content\nCardHeader(title?: string, subtitle?: string) — Header with optional title and subtitle\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nMarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\") — Renders markdown text with optional container variant\nCallout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding) — Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.\nTextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string) — Text callout with variant, title, and description\nImage(alt: string, src?: string) — Image with alt text and optional URL\nImageBlock(src: string, alt?: string) — Image block with loading state\nImageGallery(images: {src: string, alt?: string, details?: string}[]) — Gallery grid of images with modal preview\nCodeBlock(language: string, codeString: string) — Syntax-highlighted code block\nSeparator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean) — Visual divider between content sections\nInlineHeader(heading: string, description?: string) — Compact section heading with an optional one-line description, for use inside cards.\n- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).\n- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card.\n\n### Tables\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\nEditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[]) — Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field\n- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).\n- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.\n\n### Charts (2D)\nBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number) — Vertical bars; use for comparing values across categories with one or more series\nLineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Lines over categories; use for trends and continuous data over time\nAreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Filled area under lines; use for cumulative totals or volume trends over time\nRadarChart(labels: string[], series: Series[]) — Spider/web chart; use for comparing multiple variables across one or more entities\nHorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string) — Horizontal bars; prefer when category labels are long or for ranked lists\nSeries(category: string, values: number[]) — One data series\n\n### Charts (1D)\nPieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\") — Circular slices; use plucked arrays: PieChart(data.categories, data.values)\nRadialChart(labels: string[], values: number[]) — Radial bars; use plucked arrays: RadialChart(data.categories, data.values)\nSingleStackedBarChart(labels: string[], values: number[]) — Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)\nSlice(category: string, value: number) — One slice with label and numeric value\n\n### Charts (Scatter)\nScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string) — X/Y scatter plot; use for correlations, distributions, and clustering\nScatterSeries(name: string, points: Point[]) — Named dataset\nPoint(x: number, y: number, z?: number) — Data point with numeric coordinates\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nLabel(text: string) — Text label\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nTextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nDatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSlider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding) — Numeric slider input; supports continuous and discrete (stepped) variants\nCheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)\nCheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)\nRadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nRadioItem(label: string, description: string, value: string)\nSwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>) — Group of switch toggles\nSwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean) — Individual switch toggle\nChips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.\nChipItem(value: string, label: string, icon?: Icon, disabled?: boolean) — A single selectable chip inside a Chips group, with a value, label and optional icon.\nOptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.\nOptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean) — A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.\n- Chips: compact single/multiple selection pills. Use ChipItem references for each option.\n- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.\n- Define EACH FormControl as its own reference — do NOT inline all controls in one array.\n- NEVER nest Form inside Form.\n- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).\n- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }\n- The renderer shows error messages automatically — do NOT generate error text in the UI\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nIcon(name: string, category?: string) — A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.\nIconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\") — Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.\n- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.\n\n### Lists & Follow-ups\nListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\") — A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.\nListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression) — Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.\nFollowUpBlock(items: FollowUpItem[]) — List of clickable follow-up suggestions placed at the end of a response\nFollowUpItem(text: string) — Clickable follow-up suggestion — when clicked, sends text as user message\n- Use ListBlock with ListItem references for numbered lists.\n- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.\n- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.\n- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.\n- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })\n\n### Sections\nSectionBlock(sections: SectionItem[], isFoldable?: boolean) — Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section.\nSectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[]) — Section with a label and collapsible content — used inside SectionBlock\n- SectionBlock renders collapsible accordion sections that auto-open as they stream.\n- Each section needs a unique `value` id, a `trigger` label, and a `content` array.\n- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])\n- Set isFoldable=false to render sections as flat headers instead of accordion.\n\n### Layout\nTabs(items: TabItem[]) — Tabbed container\nTabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[]) — value is unique id, trigger is tab label, content is array of components\nAccordion(items: AccordionItem[]) — Collapsible sections\nAccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[]) — value is unique id, trigger is section title\nSteps(items: StepsItem[]) — Step-by-step guide\nStepsItem(title: string, details: string) — title and details text for one step\nCarousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\") — Horizontal scrollable carousel\n- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.\n- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])\n- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.\n- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.\n- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs.\n\n### Data Display\nTagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\") — tags is an array of strings; optional size sm | md | lg\nTag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\") — Styled tag/badge with optional Icon and variant\nEntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}) — Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.\n- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.\n\n### Cards\nSnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.\nSnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText) — One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).\nOverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.\nOverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline) — One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.\nContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.\nContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string) — A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.\nCompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.\nCompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button}) — A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.\nVisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.\nVisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string) — A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).\nText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nBoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nIconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\") — An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.\nImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number) — A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.\nImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean) — A full-width banner image above a bold title and optional subtitle. src must be a real image URL.\nMetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional +/- percentage trend and subtext, all on one line.\nMetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.\n- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.\n- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.\n- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.\n- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.\n- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.\n- VisualCardItem: image-first card with a BoldText body and optional Tag.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n\n## Examples\n\nExample 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }\n\nExample 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")\n\nExample 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)\n\nExample 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }\n\nExample 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")\n\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n\n- When asked about data, generate realistic/plausible data\n- Every response is a single Card(children) — children stack vertically automatically. No layout params are needed on Card.\n- Card is the only layout container. Do NOT use Stack. Use Tabs to switch between sections, Carousel for horizontal scroll.\n- Use FollowUpBlock at the END of a Card to suggest what the user can do or ask next.\n- Use ListBlock when presenting a set of options or steps; give each ListItem an action (5th argument) to make it clickable — without one the item is plain text.\n- Use SectionBlock to group long responses into collapsible sections — good for reports, FAQs, and structured content.\n- Use SectionItem inside SectionBlock: each item needs a unique value id, a trigger (header label), and a content array.\n- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])\n- IMPORTANT: Every slide in a Carousel must use the same component structure in the same order — e.g. all slides: [title, image, description, tags].\n- For forms, define one FormControl reference per field so controls can stream progressively.\n- For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).\n- Never nest Form inside Form.\n- CardHeader is the page-level heading — place it as the first child of Card; InlineHeader is a lighter subsection label for a block inside the response, and is redundant when the following component already has a heading.\n- Never use Callout or TextCallout to justify why you did what you did or for any meta-information.\n- Every image slot (Image, ImageBlock, ImageGallery, VisualCardItem/ContextCardItem bgImageSrc, ImageText, ImageTextLarge, ListItem image) requires a REAL URL from a tool result, the conversation, or the user — NEVER invent, guess, or template a URL.\n- If no image URL is in context, compose without image components — icons, gray ContextCardItems, and charts still make rich layouts.\n- Argument-order trap: Image takes alt FIRST, while ImageBlock, ImageText, and ImageTextLarge take src FIRST — alt text in a src slot ships a broken image.\n- Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items, all with the same structure; use layout \"grid\" for primary side-by-side comparison and \"carousel\" for secondary browsing.\n- The card-block action is BLOCK-LEVEL: one action shared by every card, with the clicked card's details attached automatically — keep continue_conversation context generic (e.g. \"Tell me more about this destination\"), and never use a block-level open_url since it would send every card to the same URL.\n- Card items have NO per-item action: to give each item its own external link, use CompositeCardItem with footer { button: Button(label, { type: \"open_url\", url }) } — never claim a card opens a link it cannot.\n- Text, BoldText, IconText, ImageText, ImageTextLarge and MetricIndicator* are inline building blocks used INSIDE card items — do not place them directly in the root Card.\n- EntityList size \"small\" is reserved for CompositeCardItem body content (no header/footer); use size \"default\" elsewhere.\n- Tag variant must be semantically correct (success=positive, danger=negative, warning=cautionary, info=informational, neutral=label); Tag takes an optional Icon second, so use Tag(text, icon, size, variant) when a variant is needed.\n- TagBlock takes plain strings — keep it to at most 3 tags.\n- ListBlock variant \"number\" is for ordered sequences and rankings, \"image\" for products/profiles with a real image; Steps is for ordered sequential processes only.\n- Use SectionBlock to divide a long response into independent, equally prominent topics; use Tabs when the items are alternative views of the same thing; set isFoldable=false unless a section has 4+ distinct blocks; never make SectionBlock the first Card child.\n- Accordion is for supplementary or FAQ content only — never primary information, 3-5 items max, and always the last component in its section or card.\n- Charts: LineChart/AreaChart variant \"natural\" for smooth trends and \"linear\" for precise point-to-point data; BarChart \"grouped\" for side-by-side comparison and \"stacked\" for part-to-whole; prefer HorizontalBarChart when category labels are long or numerous.\n- For large chart values, scale the data and put the unit in the axis label (e.g. yLabel \"Revenue ($k)\") instead of passing raw thousands or millions.\n- Quantitative asks get a chart (plus KPI cards where useful) in the FIRST response — do not answer numbers with prose or a table alone.\n- Table is column-oriented: each Col holds its own data array of plain strings or numbers (never components), and every column's array must have the same length.\n- Use EditableTable ONLY when the user or app explicitly asks for an editable table; default to Table for read-only data.\n- Every Form MUST have EXACTLY ONE submit Button with variant \"primary\" — that button validates the form; other buttons (secondary/tertiary escape hatches like \"Just Surprise Me\") skip validation, and there is never a reset button.\n- Prefer structured inputs (Select, Chips, OptionCards, DatePicker, Slider) over free-text Input, give every FormControl a clear label (and a hint where it prevents mistakes), and keep each field name unique within the response.\n- Validation rules ({ required: true, email: true, minLength: 8, ... }) are enforced with inline errors — use them for genuinely essential fields, but never require a free-text field where leaving it blank is meaningful.\n- Form inputs work ONLY inside a FormControl within a Form; for tappable suggestion choices OUTSIDE a form, use Buttons of continue_conversation Buttons — never a bare OptionCards or Chips.\n- Only add Buttons for real actions: form submit, open_url with a URL from a tool or the user (never fabricated), or a continue_conversation follow-up — never a button for an app action (open, download, export, edit) you cannot perform.\n- Every Button label must accurately describe what clicking it does; use \"primary\" for the main action and \"secondary\"/\"tertiary\" only for lower-emphasis supporting actions.\n- Icon: always include the category argument — it enables fallback matching when the exact lucide name is unavailable.\n- Pass sources on Card ONLY when the answer relies on real references you actually have, and cite them inline in TextContent as [1], [2] (1-based index into sources)." - }, - { - "name": "openui-default", - "spec": { - "root": "Stack", - "components": { - "Card": { - "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)", - "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." - }, - "CardHeader": { - "signature": "CardHeader(title?: string, subtitle?: string)", - "description": "Header with optional title and subtitle" - }, - "TextContent": { - "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "MarkDownRenderer": { - "signature": "MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")", - "description": "Renders markdown text with optional container variant" - }, - "Callout": { - "signature": "Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)", - "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." - }, - "TextCallout": { - "signature": "TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)", - "description": "Text callout with variant, title, and description" - }, - "Image": { - "signature": "Image(alt: string, src?: string)", - "description": "Image with alt text and optional URL" - }, - "ImageBlock": { - "signature": "ImageBlock(src: string, alt?: string)", - "description": "Image block with loading state" - }, - "ImageGallery": { - "signature": "ImageGallery(images: {src: string, alt?: string, details?: string}[])", - "description": "Gallery grid of images with modal preview" - }, - "CodeBlock": { - "signature": "CodeBlock(language: string, codeString: string)", - "description": "Syntax-highlighted code block" - }, - "InlineHeader": { - "signature": "InlineHeader(heading: string, description?: string)", - "description": "Compact section heading with an optional one-line description, for use inside cards." - }, - "Table": { - "signature": "Table(columns: Col[])", - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", - "description": "Column definition — holds label + data array" - }, - "EditableTable": { - "signature": "EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])", - "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" - }, - "BarChart": { - "signature": "BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Vertical bars; use for comparing values across categories with one or more series" - }, - "LineChart": { - "signature": "LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Lines over categories; use for trends and continuous data over time" - }, - "AreaChart": { - "signature": "AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Filled area under lines; use for cumulative totals or volume trends over time" - }, - "RadarChart": { - "signature": "RadarChart(labels: string[], series: Series[])", - "description": "Spider/web chart; use for comparing multiple variables across one or more entities" - }, - "HorizontalBarChart": { - "signature": "HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)", - "description": "Horizontal bars; prefer when category labels are long or for ranked lists" - }, - "Series": { - "signature": "Series(category: string, values: number[])", - "description": "One data series" - }, - "PieChart": { - "signature": "PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")", - "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" - }, - "RadialChart": { - "signature": "RadialChart(labels: string[], values: number[])", - "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" - }, - "SingleStackedBarChart": { - "signature": "SingleStackedBarChart(labels: string[], values: number[])", - "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" - }, - "Slice": { - "signature": "Slice(category: string, value: number)", - "description": "One slice with label and numeric value" - }, - "ScatterChart": { - "signature": "ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)", - "description": "X/Y scatter plot; use for correlations, distributions, and clustering" - }, - "ScatterSeries": { - "signature": "ScatterSeries(name: string, points: Point[])", - "description": "Named dataset" - }, - "Point": { - "signature": "Point(x: number, y: number, z?: number)", - "description": "Data point with numeric coordinates" - }, - "Form": { - "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", - "description": "Form container with fields and explicit action buttons" - }, - "FormControl": { - "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", - "description": "Field with label, input component, and optional hint text" - }, - "Label": { - "signature": "Label(text: string)", - "description": "Text label" - }, - "Input": { - "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "TextArea": { - "signature": "TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Select": { - "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", - "description": "" - }, - "SelectItem": { - "signature": "SelectItem(value: string, label: string)", - "description": "Option for Select" - }, - "DatePicker": { - "signature": "DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Slider": { - "signature": "Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "Numeric slider input; supports continuous and discrete (stepped) variants" - }, - "CheckBoxGroup": { - "signature": "CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)", - "description": "" - }, - "CheckBoxItem": { - "signature": "CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)", - "description": "" - }, - "RadioGroup": { - "signature": "RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "RadioItem": { - "signature": "RadioItem(label: string, description: string, value: string)", - "description": "" - }, - "SwitchGroup": { - "signature": "SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)", - "description": "Group of switch toggles" - }, - "SwitchItem": { - "signature": "SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)", - "description": "Individual switch toggle" - }, - "ChipItem": { - "signature": "ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)", - "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." - }, - "Chips": { - "signature": "Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", - "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." - }, - "OptionCard": { - "signature": "OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)", - "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." - }, - "OptionCards": { - "signature": "OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", - "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." - }, - "Button": { - "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", - "description": "Clickable button" - }, - "Buttons": { - "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "IconButton": { - "signature": "IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")", - "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." - }, - "Stack": { - "signature": "Stack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)", - "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." - }, - "Tabs": { - "signature": "Tabs(items: TabItem[])", - "description": "Tabbed container" - }, - "TabItem": { - "signature": "TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])", - "description": "value is unique id, trigger is tab label, content is array of components" - }, - "Accordion": { - "signature": "Accordion(items: AccordionItem[])", - "description": "Collapsible sections" - }, - "AccordionItem": { - "signature": "AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])", - "description": "value is unique id, trigger is section title" - }, - "Steps": { - "signature": "Steps(items: StepsItem[])", - "description": "Step-by-step guide" - }, - "StepsItem": { - "signature": "StepsItem(title: string, details: string)", - "description": "title and details text for one step" - }, - "Carousel": { - "signature": "Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\")", - "description": "Horizontal scrollable carousel" - }, - "Separator": { - "signature": "Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)", - "description": "Visual divider between content sections" - }, - "TagBlock": { - "signature": "TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")", - "description": "tags is an array of strings; optional size sm | md | lg" - }, - "Tag": { - "signature": "Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")", - "description": "Styled tag/badge with optional Icon and variant" - }, - "Icon": { - "signature": "Icon(name: string, category?: string)", - "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." - }, - "EntityList": { - "signature": "EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})", - "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." - }, - "ListBlock": { - "signature": "ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")", - "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." - }, - "ListItem": { - "signature": "ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)", - "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." - }, - "Text": { - "signature": "Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", - "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "BoldText": { - "signature": "BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", - "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "IconText": { - "signature": "IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")", - "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." - }, - "ImageText": { - "signature": "ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)", - "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." - }, - "ImageTextLarge": { - "signature": "ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)", - "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." - }, - "MetricIndicatorInline": { - "signature": "MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})", - "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." - }, - "MetricIndicatorWithStrikethrough": { - "signature": "MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})", - "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." - }, - "SnippetCardItem": { - "signature": "SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)", - "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." - }, - "SnippetCardBlock": { - "signature": "SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." - }, - "OverviewCardItem": { - "signature": "OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)", - "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." - }, - "OverviewCardBlock": { - "signature": "OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." - }, - "ContextCardItem": { - "signature": "ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)", - "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." - }, - "ContextCardBlock": { - "signature": "ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." - }, - "CompositeCardItem": { - "signature": "CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})", - "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." - }, - "CompositeCardBlock": { - "signature": "CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." - }, - "VisualCardItem": { - "signature": "VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)", - "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." - }, - "VisualCardBlock": { - "signature": "VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." - }, - "Modal": { - "signature": "Modal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\")", - "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." - } - }, - "componentGroups": [ - { - "name": "Layout", - "components": [ - "Stack", - "Tabs", - "TabItem", - "Accordion", - "AccordionItem", - "Steps", - "StepsItem", - "Carousel", - "Separator", - "Modal" - ], - "notes": [ - "- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.", - "- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.", - "- Use nested Stacks when you need explicit rows/sections.", - "- Show/hide sections: $editId != \"\" ? Card([editForm]) : null", - "- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.", - "- Use Tabs for alternative views (chart types, data sections) — no $variable needed", - "- Shared filter across Tabs: same $days binding in Query args works across all TabItems" - ] - }, - { - "name": "Content", - "components": [ - "Card", - "CardHeader", - "TextContent", - "MarkDownRenderer", - "Callout", - "TextCallout", - "Image", - "ImageBlock", - "ImageGallery", - "CodeBlock", - "InlineHeader" - ], - "notes": [ - "- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).", - "- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.", - "- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null", - "- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])" - ] - }, - { - "name": "Tables", - "components": [ - "Table", - "Col", - "EditableTable" - ], - "notes": [ - "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", - "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.", - "- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName", - "- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))", - "- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))", - "- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data", - "- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input", - "- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts", - "- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")" - ] - }, - { - "name": "Charts (2D)", - "components": [ - "BarChart", - "LineChart", - "AreaChart", - "RadarChart", - "HorizontalBarChart", - "Series" - ], - "notes": [ - "- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])", - "- Use Cards to wrap charts with CardHeader for titled sections", - "- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data", - "- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])" - ] - }, - { - "name": "Charts (1D)", - "components": [ - "PieChart", - "RadialChart", - "SingleStackedBarChart", - "Slice" - ], - "notes": [ - "- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:", - "- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`", - "- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`" - ] - }, - { - "name": "Charts (Scatter)", - "components": [ - "ScatterChart", - "ScatterSeries", - "Point" - ] - }, - { - "name": "Forms", - "components": [ - "Form", - "FormControl", - "Label", - "Input", - "TextArea", - "Select", - "SelectItem", - "DatePicker", - "Slider", - "CheckBoxGroup", - "CheckBoxItem", - "RadioGroup", - "RadioItem", - "SwitchGroup", - "SwitchItem", - "Chips", - "ChipItem", - "OptionCards", - "OptionCard" - ], - "notes": [ - "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", - "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", - "- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.", - "- NEVER nest Form inside Form — each Form should be a standalone container.", - "- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.", - "- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}", - "- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric", - "- The renderer shows error messages automatically — do NOT generate error text in the UI", - "- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField", - "- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal." - ] - }, - { - "name": "Buttons", - "components": [ - "Button", - "Buttons", - "IconButton" - ], - "notes": [ - "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.", - "- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))" - ] - }, - { - "name": "Data Display", - "components": [ - "TagBlock", - "Tag", - "Icon", - "EntityList", - "ListBlock", - "ListItem" - ], - "notes": [ - "- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")", - "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.", - "- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional." - ] - }, - { - "name": "Cards", - "components": [ - "SnippetCardBlock", - "SnippetCardItem", - "OverviewCardBlock", - "OverviewCardItem", - "ContextCardBlock", - "ContextCardItem", - "CompositeCardBlock", - "CompositeCardItem", - "VisualCardBlock", - "VisualCardItem", - "Text", - "BoldText", - "IconText", - "ImageText", - "ImageTextLarge", - "MetricIndicatorInline", - "MetricIndicatorWithStrikethrough" - ], - "notes": [ - "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", - "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", - "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", - "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", - "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", - "- VisualCardItem: image-first card with a BoldText body and optional Tag.", - "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card." - ] - } - ], - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "Card": { - "$ref": "#/$defs/Card" - }, - "CardHeader": { - "$ref": "#/$defs/CardHeader" - }, - "TextContent": { - "$ref": "#/$defs/TextContent" - }, - "MarkDownRenderer": { - "$ref": "#/$defs/MarkDownRenderer" - }, - "Callout": { - "$ref": "#/$defs/Callout" - }, - "TextCallout": { - "$ref": "#/$defs/TextCallout" - }, - "Image": { - "$ref": "#/$defs/Image" - }, - "ImageBlock": { - "$ref": "#/$defs/ImageBlock" - }, - "ImageGallery": { - "$ref": "#/$defs/ImageGallery" - }, - "CodeBlock": { - "$ref": "#/$defs/CodeBlock" - }, - "InlineHeader": { - "$ref": "#/$defs/InlineHeader" - }, - "Table": { - "$ref": "#/$defs/Table" - }, - "Col": { - "$ref": "#/$defs/Col" - }, - "EditableTable": { - "$ref": "#/$defs/EditableTable" - }, - "BarChart": { - "$ref": "#/$defs/BarChart" - }, - "LineChart": { - "$ref": "#/$defs/LineChart" - }, - "AreaChart": { - "$ref": "#/$defs/AreaChart" - }, - "RadarChart": { - "$ref": "#/$defs/RadarChart" - }, - "HorizontalBarChart": { - "$ref": "#/$defs/HorizontalBarChart" - }, - "Series": { - "$ref": "#/$defs/Series" - }, - "PieChart": { - "$ref": "#/$defs/PieChart" - }, - "RadialChart": { - "$ref": "#/$defs/RadialChart" - }, - "SingleStackedBarChart": { - "$ref": "#/$defs/SingleStackedBarChart" - }, - "Slice": { - "$ref": "#/$defs/Slice" - }, - "ScatterChart": { - "$ref": "#/$defs/ScatterChart" - }, - "ScatterSeries": { - "$ref": "#/$defs/ScatterSeries" - }, - "Point": { - "$ref": "#/$defs/Point" - }, - "Form": { - "$ref": "#/$defs/Form" - }, - "FormControl": { - "$ref": "#/$defs/FormControl" - }, - "Label": { - "$ref": "#/$defs/Label" - }, - "Input": { - "$ref": "#/$defs/Input" - }, - "TextArea": { - "$ref": "#/$defs/TextArea" - }, - "Select": { - "$ref": "#/$defs/Select" - }, - "SelectItem": { - "$ref": "#/$defs/SelectItem" - }, - "DatePicker": { - "$ref": "#/$defs/DatePicker" - }, - "Slider": { - "$ref": "#/$defs/Slider" - }, - "CheckBoxGroup": { - "$ref": "#/$defs/CheckBoxGroup" - }, - "CheckBoxItem": { - "$ref": "#/$defs/CheckBoxItem" - }, - "RadioGroup": { - "$ref": "#/$defs/RadioGroup" - }, - "RadioItem": { - "$ref": "#/$defs/RadioItem" - }, - "SwitchGroup": { - "$ref": "#/$defs/SwitchGroup" - }, - "SwitchItem": { - "$ref": "#/$defs/SwitchItem" - }, - "ChipItem": { - "$ref": "#/$defs/ChipItem" - }, - "Chips": { - "$ref": "#/$defs/Chips" - }, - "OptionCard": { - "$ref": "#/$defs/OptionCard" - }, - "OptionCards": { - "$ref": "#/$defs/OptionCards" - }, - "Button": { - "$ref": "#/$defs/Button" - }, - "Buttons": { - "$ref": "#/$defs/Buttons" - }, - "IconButton": { - "$ref": "#/$defs/IconButton" - }, - "Stack": { - "$ref": "#/$defs/Stack" - }, - "Tabs": { - "$ref": "#/$defs/Tabs" - }, - "TabItem": { - "$ref": "#/$defs/TabItem" - }, - "Accordion": { - "$ref": "#/$defs/Accordion" - }, - "AccordionItem": { - "$ref": "#/$defs/AccordionItem" - }, - "Steps": { - "$ref": "#/$defs/Steps" - }, - "StepsItem": { - "$ref": "#/$defs/StepsItem" - }, - "Carousel": { - "$ref": "#/$defs/Carousel" - }, - "Separator": { - "$ref": "#/$defs/Separator" - }, - "TagBlock": { - "$ref": "#/$defs/TagBlock" - }, - "Tag": { - "$ref": "#/$defs/Tag" - }, - "Icon": { - "$ref": "#/$defs/Icon" - }, - "EntityList": { - "$ref": "#/$defs/EntityList" - }, - "ListBlock": { - "$ref": "#/$defs/ListBlock" - }, - "ListItem": { - "$ref": "#/$defs/ListItem" - }, - "Text": { - "$ref": "#/$defs/Text" - }, - "BoldText": { - "$ref": "#/$defs/BoldText" - }, - "IconText": { - "$ref": "#/$defs/IconText" - }, - "ImageText": { - "$ref": "#/$defs/ImageText" - }, - "ImageTextLarge": { - "$ref": "#/$defs/ImageTextLarge" - }, - "MetricIndicatorInline": { - "$ref": "#/$defs/MetricIndicatorInline" - }, - "MetricIndicatorWithStrikethrough": { - "$ref": "#/$defs/MetricIndicatorWithStrikethrough" - }, - "SnippetCardItem": { - "$ref": "#/$defs/SnippetCardItem" - }, - "SnippetCardBlock": { - "$ref": "#/$defs/SnippetCardBlock" - }, - "OverviewCardItem": { - "$ref": "#/$defs/OverviewCardItem" - }, - "OverviewCardBlock": { - "$ref": "#/$defs/OverviewCardBlock" - }, - "ContextCardItem": { - "$ref": "#/$defs/ContextCardItem" - }, - "ContextCardBlock": { - "$ref": "#/$defs/ContextCardBlock" - }, - "CompositeCardItem": { - "$ref": "#/$defs/CompositeCardItem" - }, - "CompositeCardBlock": { - "$ref": "#/$defs/CompositeCardBlock" - }, - "VisualCardItem": { - "$ref": "#/$defs/VisualCardItem" - }, - "VisualCardBlock": { - "$ref": "#/$defs/VisualCardBlock" - }, - "Modal": { - "$ref": "#/$defs/Modal" - } - }, - "required": [ - "Card", - "CardHeader", - "TextContent", - "MarkDownRenderer", - "Callout", - "TextCallout", - "Image", - "ImageBlock", - "ImageGallery", - "CodeBlock", - "InlineHeader", - "Table", - "Col", - "EditableTable", - "BarChart", - "LineChart", - "AreaChart", - "RadarChart", - "HorizontalBarChart", - "Series", - "PieChart", - "RadialChart", - "SingleStackedBarChart", - "Slice", - "ScatterChart", - "ScatterSeries", - "Point", - "Form", - "FormControl", - "Label", - "Input", - "TextArea", - "Select", - "SelectItem", - "DatePicker", - "Slider", - "CheckBoxGroup", - "CheckBoxItem", - "RadioGroup", - "RadioItem", - "SwitchGroup", - "SwitchItem", - "ChipItem", - "Chips", - "OptionCard", - "OptionCards", - "Button", - "Buttons", - "IconButton", - "Stack", - "Tabs", - "TabItem", - "Accordion", - "AccordionItem", - "Steps", - "StepsItem", - "Carousel", - "Separator", - "TagBlock", - "Tag", - "Icon", - "EntityList", - "ListBlock", - "ListItem", - "Text", - "BoldText", - "IconText", - "ImageText", - "ImageTextLarge", - "MetricIndicatorInline", - "MetricIndicatorWithStrikethrough", - "SnippetCardItem", - "SnippetCardBlock", - "OverviewCardItem", - "OverviewCardBlock", - "ContextCardItem", - "ContextCardBlock", - "CompositeCardItem", - "CompositeCardBlock", - "VisualCardItem", - "VisualCardBlock", - "Modal" - ], - "additionalProperties": false, - "$defs": { - "Card": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - }, - { - "$ref": "#/$defs/Tabs" - }, - { - "$ref": "#/$defs/Carousel" - }, - { - "$ref": "#/$defs/Stack" - } - ] - } - }, - "variant": { - "type": "string", - "enum": [ - "card", - "sunk", - "clear" - ] - }, - "direction": { - "type": "string", - "enum": [ - "row", - "column" - ] - }, - "gap": { - "type": "string", - "enum": [ - "none", - "xs", - "s", - "m", - "l", - "xl", - "2xl" - ] - }, - "align": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "stretch", - "baseline" - ] - }, - "justify": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "between", - "around", - "evenly" - ] - }, - "wrap": { - "type": "boolean" - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." - }, - "TextContent": { - "type": "object", - "properties": { - "text": { - "type": "string" - }, - "size": { - "type": "string", - "enum": [ - "small", - "default", - "large", - "small-heavy", - "large-heavy" - ] - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "MarkDownRenderer": { - "type": "object", - "properties": { - "textMarkdown": { - "type": "string" - }, - "variant": { - "type": "string", - "enum": [ - "clear", - "card", - "sunk" - ] - } - }, - "required": [ - "textMarkdown" - ], - "additionalProperties": false, - "description": "Renders markdown text with optional container variant" - }, - "CardHeader": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - } - }, - "additionalProperties": false, - "description": "Header with optional title and subtitle" - }, - "Callout": { - "type": "object", - "properties": { - "variant": { - "type": "string", - "enum": [ - "info", - "warning", - "error", - "success", - "neutral" - ] - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "visible": { - "type": "boolean" - } - }, - "required": [ - "variant", - "title", - "description" - ], - "additionalProperties": false, - "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." - }, - "TextCallout": { - "type": "object", - "properties": { - "variant": { - "type": "string", - "enum": [ - "neutral", - "info", - "warning", - "success", - "danger" - ] - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - } - }, - "additionalProperties": false, - "description": "Text callout with variant, title, and description" - }, - "CodeBlock": { - "type": "object", - "properties": { - "language": { - "type": "string" - }, - "codeString": { - "type": "string" - } - }, - "required": [ - "language", - "codeString" - ], - "additionalProperties": false, - "description": "Syntax-highlighted code block" - }, - "Image": { - "type": "object", - "properties": { - "alt": { - "type": "string" - }, - "src": { - "type": "string" - } - }, - "required": [ - "alt" - ], - "additionalProperties": false, - "description": "Image with alt text and optional URL" - }, - "ImageBlock": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - } - }, - "required": [ - "src" - ], - "additionalProperties": false, - "description": "Image block with loading state" - }, - "ImageGallery": { - "type": "object", - "properties": { - "images": { - "type": "array", - "items": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "details": { - "type": "string" - } - }, - "required": [ - "src" - ], - "additionalProperties": false - } - } - }, - "required": [ - "images" - ], - "additionalProperties": false, - "description": "Gallery grid of images with modal preview" - }, - "Separator": { - "type": "object", - "properties": { - "orientation": { - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - }, - "decorative": { - "type": "boolean" - } - }, - "additionalProperties": false, - "description": "Visual divider between content sections" - }, - "HorizontalBarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "grouped", - "stacked" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Horizontal bars; prefer when category labels are long or for ranked lists" - }, - "Series": { - "type": "object", - "properties": { - "category": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "category", - "values" - ], - "additionalProperties": false, - "description": "One data series" - }, - "RadarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Spider/web chart; use for comparing multiple variables across one or more entities" - }, - "PieChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - }, - "variant": { - "type": "string", - "enum": [ - "pie", - "donut" - ] - }, - "appearance": { - "type": "string", - "enum": [ - "circular", - "semiCircular" - ] - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" - }, - "RadialChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" - }, - "SingleStackedBarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" - }, - "ScatterChart": { - "type": "object", - "properties": { - "datasets": { - "type": "array", - "items": { - "$ref": "#/$defs/ScatterSeries" - } - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - } - }, - "required": [ - "datasets" - ], - "additionalProperties": false, - "description": "X/Y scatter plot; use for correlations, distributions, and clustering" - }, - "ScatterSeries": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "points": { - "type": "array", - "items": { - "$ref": "#/$defs/Point" - } - } - }, - "required": [ - "name", - "points" - ], - "additionalProperties": false, - "description": "Named dataset" - }, - "Point": { - "type": "object", - "properties": { - "x": { - "type": "number" - }, - "y": { - "type": "number" - }, - "z": { - "type": "number" - } - }, - "required": [ - "x", - "y" - ], - "additionalProperties": false, - "description": "Data point with numeric coordinates" - }, - "AreaChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "linear", - "natural", - "step" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Filled area under lines; use for cumulative totals or volume trends over time" - }, - "BarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "grouped", - "stacked" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Vertical bars; use for comparing values across categories with one or more series" - }, - "LineChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "linear", - "natural", - "step" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Lines over categories; use for trends and continuous data over time" - }, - "Table": { - "type": "object", - "properties": { - "columns": { - "type": "array", - "items": { - "$ref": "#/$defs/Col" - } - } - }, - "required": [ - "columns" - ], - "additionalProperties": false, - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "data": {}, - "type": { - "type": "string", - "enum": [ - "string", - "number", - "action" - ] - } - }, - "required": [ - "label", - "data" - ], - "additionalProperties": false, - "description": "Column definition — holds label + data array" - }, - "TagBlock": { - "type": "object", - "properties": { - "tags": { - "type": "array", - "items": { - "type": "string" - } - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "tags" - ], - "additionalProperties": false, - "description": "tags is an array of strings; optional size sm | md | lg" - }, - "Form": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "buttons": { - "$ref": "#/$defs/Buttons" - }, - "fields": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/FormControl" - } - } - }, - "required": [ - "name", - "buttons", - "fields" - ], - "additionalProperties": false, - "description": "Form container with fields and explicit action buttons" - }, - "Buttons": { - "type": "object", - "properties": { - "buttons": { - "type": "array", - "items": { - "$ref": "#/$defs/Button" - } - }, - "direction": { - "type": "string", - "enum": [ - "row", - "column" - ] - } - }, - "required": [ - "buttons" - ], - "additionalProperties": false, - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "Button": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "variant": { - "type": "string", - "enum": [ - "primary", - "secondary", - "tertiary" - ] - }, - "type": { - "type": "string", - "enum": [ - "normal", - "destructive" - ] - }, - "size": { - "type": "string", - "enum": [ - "extra-small", - "small", - "medium", - "large" - ] - } - }, - "required": [ - "label" - ], - "additionalProperties": false, - "description": "Clickable button" - }, - "FormControl": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "input": { - "anyOf": [ - { - "$ref": "#/$defs/Input" - }, - { - "$ref": "#/$defs/TextArea" - }, - { - "$ref": "#/$defs/Select" - }, - { - "$ref": "#/$defs/DatePicker" - }, - { - "$ref": "#/$defs/Slider" - }, - { - "$ref": "#/$defs/CheckBoxGroup" - }, - { - "$ref": "#/$defs/RadioGroup" - }, - { - "$ref": "#/$defs/Chips" - }, - { - "$ref": "#/$defs/OptionCards" - } - ] - }, - "hint": { - "type": "string" - } - }, - "required": [ - "label", - "input" - ], - "additionalProperties": false, - "description": "Field with label, input component, and optional hint text" - }, - "Input": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "placeholder": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "text", - "email", - "password", - "number", - "url" - ] - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "TextArea": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "placeholder": { - "type": "string" - }, - "rows": { - "type": "number" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "Select": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/SelectItem" - } - }, - "placeholder": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - }, - "size": { - "type": "string", - "enum": [ - "small", - "medium", - "large" - ] - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "SelectItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false, - "description": "Option for Select" - }, - "DatePicker": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "mode": { - "type": "string", - "enum": [ - "single", - "range" - ] - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": {} - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "Slider": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "variant": { - "type": "string", - "enum": [ - "continuous", - "discrete" - ] - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "step": { - "type": "number" - }, - "defaultValue": { - "type": "array", - "items": { - "type": "number" - } - }, - "label": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "name", - "variant", - "min", - "max" - ], - "additionalProperties": false, - "description": "Numeric slider input; supports continuous and discrete (stepped) variants" - }, - "CheckBoxGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/CheckBoxItem" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": { - "type": "boolean" - } - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "CheckBoxItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "defaultChecked": { - "type": "boolean" - } - }, - "required": [ - "label", - "description", - "name" - ], - "additionalProperties": false - }, - "RadioGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/RadioItem" - } - }, - "defaultValue": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "RadioItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "value": { - "type": "string" - } - }, - "required": [ - "label", - "description", - "value" - ], - "additionalProperties": false - }, - "Chips": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "type": { - "default": "multiple", - "type": "string", - "enum": [ - "single", - "multiple" - ] - }, - "items": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/ChipItem" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "defaultValue": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - } - }, - "required": [ - "name", - "type", - "items" - ], - "additionalProperties": false, - "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." - }, - "ChipItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "disabled": { - "type": "boolean" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false, - "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." - }, - "Icon": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "category": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false, - "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." - }, - "OptionCards": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "type": { - "default": "single", - "type": "string", - "enum": [ - "single", - "multiple" - ] - }, - "items": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/OptionCard" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "defaultValue": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - } - }, - "required": [ - "name", - "type", - "items" - ], - "additionalProperties": false, - "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." - }, - "OptionCard": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "topContent": { - "anyOf": [ - { - "$ref": "#/$defs/Icon" - }, - { - "$ref": "#/$defs/Image" - } - ] - }, - "disabled": { - "type": "boolean" - } - }, - "required": [ - "value", - "title" - ], - "additionalProperties": false, - "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." - }, - "IconButton": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "variant": { - "type": "string", - "enum": [ - "primary", - "secondary", - "tertiary" - ] - }, - "size": { - "type": "string", - "enum": [ - "extra-small", - "small", - "medium", - "large" - ] - }, - "shape": { - "type": "string", - "enum": [ - "square", - "circle" - ] - } - }, - "required": [ - "name", - "icon" - ], - "additionalProperties": false, - "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." - }, - "Steps": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/StepsItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Step-by-step guide" - }, - "StepsItem": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "details": { - "type": "string" - } - }, - "required": [ - "title", - "details" - ], - "additionalProperties": false, - "description": "title and details text for one step" - }, - "InlineHeader": { - "type": "object", - "properties": { - "heading": { - "type": "string" - }, - "description": { - "type": "string" - } - }, - "required": [ - "heading" - ], - "additionalProperties": false, - "description": "Compact section heading with an optional one-line description, for use inside cards." - }, - "EntityList": { - "type": "object", - "properties": { - "rows": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - } - }, - "size": { - "default": "default", - "type": "string", - "enum": [ - "small", - "default" - ] - }, - "header": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - }, - "footer": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - } - }, - "required": [ - "rows", - "size" - ], - "additionalProperties": false, - "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." - }, - "EditableTable": { - "type": "object", - "properties": { - "name": { - "default": "", - "type": "string" - }, - "columns": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "text", - "number", - "date-single", - "select", - "url" - ] - }, - "key": { - "default": "default", - "type": "string" - }, - "header": { - "default": "", - "type": "string" - }, - "width": { - "type": "number" - }, - "options": { - "type": "array", - "items": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false - } - } - }, - "required": [ - "type", - "key", - "header" - ], - "additionalProperties": false - } - }, - "data": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - } - } - }, - "required": [ - "id", - "values" - ], - "additionalProperties": false - } - } - }, - "required": [ - "name", - "columns", - "data" - ], - "additionalProperties": false, - "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" - }, - "SnippetCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/SnippetCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." - }, - "SnippetCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "lhs": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - } - ] - }, - "rhs": { - "anyOf": [ - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/BoldText" - } - ] - } - }, - "required": [ - "lhs" - ], - "additionalProperties": false, - "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." - }, - "IconText": { - "type": "object", - "properties": { - "icon": { - "$ref": "#/$defs/Icon" - }, - "iconVariant": { - "default": "neutral", - "type": "string", - "enum": [ - "neutral", - "info", - "success", - "warning", - "danger", - "inverted", - "filled", - "soft" - ] - }, - "iconSize": { - "default": "m", - "type": "string", - "enum": [ - "xs", - "s", - "m", - "l", - "xl", - "sm", - "md", - "lg" - ] - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - }, - "layout": { - "default": "horizontal", - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - } - }, - "required": [ - "icon", - "iconVariant", - "iconSize", - "title", - "bold", - "layout" - ], - "additionalProperties": false, - "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." - }, - "ImageText": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - }, - "layout": { - "default": "horizontal", - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - }, - "imageSize": { - "type": "number" - } - }, - "required": [ - "src", - "title", - "bold", - "layout" - ], - "additionalProperties": false, - "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." - }, - "Text": { - "type": "object", - "properties": { - "variant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - }, - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "subtextVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number", - "metric" - ] - }, - "size": { - "default": "sm", - "type": "string", - "enum": [ - "xs", - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "variant", - "value", - "subtextVariant", - "size" - ], - "additionalProperties": false, - "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "BoldText": { - "type": "object", - "properties": { - "variant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - }, - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "subtextVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number", - "metric" - ] - }, - "size": { - "default": "sm", - "type": "string", - "enum": [ - "xs", - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "variant", - "value", - "subtextVariant", - "size" - ], - "additionalProperties": false, - "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "OverviewCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/OverviewCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." - }, - "OverviewCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "top": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - }, - { - "$ref": "#/$defs/Text" - } - ] - }, - "bottom": { - "$ref": "#/$defs/MetricIndicatorInline" - } - }, - "required": [ - "top" - ], - "additionalProperties": false, - "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." - }, - "MetricIndicatorInline": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "trend": { - "type": "object", - "properties": { - "direction": { - "type": "string", - "enum": [ - "up", - "down" - ] - }, - "value": { - "type": "number" - } - }, - "required": [ - "direction", - "value" - ], - "additionalProperties": false - } - }, - "required": [ - "value" - ], - "additionalProperties": false, - "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." - }, - "ContextCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/ContextCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." - }, - "ContextCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "title": { - "anyOf": [ - { - "type": "string" - }, - { - "$ref": "#/$defs/Tag" - } - ] - }, - "body": { - "type": "string" - }, - "bgColor": { - "type": "string", - "enum": [ - "gray" - ] - }, - "bgImageSrc": { - "type": "string" - }, - "bgImageAlt": { - "type": "string" - } - }, - "required": [ - "title" - ], - "additionalProperties": false, - "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." - }, - "Tag": { - "type": "object", - "properties": { - "text": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - }, - "variant": { - "type": "string", - "enum": [ - "neutral", - "info", - "success", - "warning", - "danger" - ] - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Styled tag/badge with optional Icon and variant" - }, - "CompositeCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/CompositeCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." - }, - "CompositeCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "header": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - }, - { - "$ref": "#/$defs/ImageTextLarge" - }, - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/Image" - } - ] - }, - "body": { - "default": [], - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/BoldText" - }, - { - "$ref": "#/$defs/MetricIndicatorInline" - }, - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/ListBlock" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/EntityList" - } - ] - } - }, - "footer": { - "type": "object", - "properties": { - "price": { - "anyOf": [ - { - "$ref": "#/$defs/BoldText" - }, - { - "$ref": "#/$defs/MetricIndicatorWithStrikethrough" - } - ] - }, - "button": { - "$ref": "#/$defs/Button" - } - }, - "additionalProperties": false - } - }, - "required": [ - "body" - ], - "additionalProperties": false, - "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." - }, - "ImageTextLarge": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - } - }, - "required": [ - "src", - "title", - "bold" - ], - "additionalProperties": false, - "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." - }, - "ListBlock": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/ListItem" - } - }, - "variant": { - "type": "string", - "enum": [ - "number", - "image" - ] - }, - "size": { - "type": "string", - "enum": [ - "default", - "small" - ] - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." - }, - "ListItem": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "image": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - } - }, - "required": [ - "src", - "alt" - ], - "additionalProperties": false - }, - "actionLabel": { - "type": "string" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "title" - ], - "additionalProperties": false, - "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." - }, - "MetricIndicatorWithStrikethrough": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "previousValue": { - "type": "string" - }, - "trend": { - "type": "object", - "properties": { - "direction": { - "type": "string", - "enum": [ - "up", - "down" - ] - }, - "value": { - "type": "number" - } - }, - "required": [ - "direction", - "value" - ], - "additionalProperties": false - } - }, - "required": [ - "value" - ], - "additionalProperties": false, - "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." - }, - "VisualCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/VisualCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." - }, - "VisualCardItem": { - "type": "object", - "properties": { - "body": { - "$ref": "#/$defs/BoldText" - }, - "id": { - "type": "string" - }, - "bgImageSrc": { - "type": "string" - }, - "tag": { - "$ref": "#/$defs/Tag" - }, - "bgImageAlt": { - "type": "string" - } - }, - "required": [ - "body" - ], - "additionalProperties": false, - "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." - }, - "Tabs": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/TabItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Tabbed container" - }, - "TabItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "trigger": { - "type": "string" - }, - "content": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - } - }, - "required": [ - "value", - "trigger", - "content" - ], - "additionalProperties": false, - "description": "value is unique id, trigger is tab label, content is array of components" - }, - "Carousel": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - } - }, - "variant": { - "type": "string", - "enum": [ - "card", - "sunk" - ] - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Horizontal scrollable carousel" - }, - "Stack": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": {} - }, - "direction": { - "type": "string", - "enum": [ - "row", - "column" - ] - }, - "gap": { - "type": "string", - "enum": [ - "none", - "xs", - "s", - "m", - "l", - "xl", - "2xl" - ] - }, - "align": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "stretch", - "baseline" - ] - }, - "justify": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "between", - "around", - "evenly" - ] - }, - "wrap": { - "type": "boolean" - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." - }, - "Slice": { - "type": "object", - "properties": { - "category": { - "type": "string" - }, - "value": { - "type": "number" - } - }, - "required": [ - "category", - "value" - ], - "additionalProperties": false, - "description": "One slice with label and numeric value" - }, - "Label": { - "type": "object", - "properties": { - "text": { - "type": "string" - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Text label" - }, - "SwitchGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/SwitchItem" - } - }, - "variant": { - "type": "string", - "enum": [ - "clear", - "card", - "sunk" - ] - }, - "value": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": { - "type": "boolean" - } - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false, - "description": "Group of switch toggles" - }, - "SwitchItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "defaultChecked": { - "type": "boolean" - } - }, - "required": [ - "name" - ], - "additionalProperties": false, - "description": "Individual switch toggle" - }, - "Accordion": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/AccordionItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Collapsible sections" - }, - "AccordionItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "trigger": { - "type": "string" - }, - "content": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - } - }, - "required": [ - "value", - "trigger", - "content" - ], - "additionalProperties": false, - "description": "value is unique id, trigger is section title" - }, - "Modal": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "open": { - "type": "boolean" - }, - "children": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "title", - "children" - ], - "additionalProperties": false, - "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." - } - } - } - }, - "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Stack(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Layout\nStack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean) — Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\".\nTabs(items: TabItem[]) — Tabbed container\nTabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[]) — value is unique id, trigger is tab label, content is array of components\nAccordion(items: AccordionItem[]) — Collapsible sections\nAccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[]) — value is unique id, trigger is section title\nSteps(items: StepsItem[]) — Step-by-step guide\nStepsItem(title: string, details: string) — title and details text for one step\nCarousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\") — Horizontal scrollable carousel\nSeparator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean) — Visual divider between content sections\nModal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\") — Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children.\n- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.\n- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.\n- Use nested Stacks when you need explicit rows/sections.\n- Show/hide sections: $editId != \"\" ? Card([editForm]) : null\n- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.\n- Use Tabs for alternative views (chart types, data sections) — no $variable needed\n- Shared filter across Tabs: same $days binding in Query args works across all TabItems\n\n### Content\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean) — Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts.\nCardHeader(title?: string, subtitle?: string) — Header with optional title and subtitle\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nMarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\") — Renders markdown text with optional container variant\nCallout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding) — Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.\nTextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string) — Text callout with variant, title, and description\nImage(alt: string, src?: string) — Image with alt text and optional URL\nImageBlock(src: string, alt?: string) — Image block with loading state\nImageGallery(images: {src: string, alt?: string, details?: string}[]) — Gallery grid of images with modal preview\nCodeBlock(language: string, codeString: string) — Syntax-highlighted code block\nInlineHeader(heading: string, description?: string) — Compact section heading with an optional one-line description, for use inside cards.\n- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).\n- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.\n- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null\n- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])\n\n### Tables\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\nEditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[]) — Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field\n- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).\n- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.\n- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName\n- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))\n- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))\n- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data\n- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input\n- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts\n- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")\n\n### Charts (2D)\nBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number) — Vertical bars; use for comparing values across categories with one or more series\nLineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Lines over categories; use for trends and continuous data over time\nAreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Filled area under lines; use for cumulative totals or volume trends over time\nRadarChart(labels: string[], series: Series[]) — Spider/web chart; use for comparing multiple variables across one or more entities\nHorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string) — Horizontal bars; prefer when category labels are long or for ranked lists\nSeries(category: string, values: number[]) — One data series\n- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])\n- Use Cards to wrap charts with CardHeader for titled sections\n- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data\n- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])\n\n### Charts (1D)\nPieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\") — Circular slices; use plucked arrays: PieChart(data.categories, data.values)\nRadialChart(labels: string[], values: number[]) — Radial bars; use plucked arrays: RadialChart(data.categories, data.values)\nSingleStackedBarChart(labels: string[], values: number[]) — Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)\nSlice(category: string, value: number) — One slice with label and numeric value\n- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:\n- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`\n- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`\n\n### Charts (Scatter)\nScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string) — X/Y scatter plot; use for correlations, distributions, and clustering\nScatterSeries(name: string, points: Point[]) — Named dataset\nPoint(x: number, y: number, z?: number) — Data point with numeric coordinates\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nLabel(text: string) — Text label\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nTextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nDatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSlider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding) — Numeric slider input; supports continuous and discrete (stepped) variants\nCheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)\nCheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)\nRadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nRadioItem(label: string, description: string, value: string)\nSwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>) — Group of switch toggles\nSwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean) — Individual switch toggle\nChips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.\nChipItem(value: string, label: string, icon?: Icon, disabled?: boolean) — A single selectable chip inside a Chips group, with a value, label and optional icon.\nOptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.\nOptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean) — A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.\n- Chips: compact single/multiple selection pills. Use ChipItem references for each option.\n- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.\n- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.\n- NEVER nest Form inside Form — each Form should be a standalone container.\n- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.\n- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}\n- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric\n- The renderer shows error messages automatically — do NOT generate error text in the UI\n- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField\n- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal.\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nIconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\") — Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.\n- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.\n- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))\n\n### Data Display\nTagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\") — tags is an array of strings; optional size sm | md | lg\nTag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\") — Styled tag/badge with optional Icon and variant\nIcon(name: string, category?: string) — A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.\nEntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}) — Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.\nListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\") — A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.\nListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression) — Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.\n- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")\n- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.\n- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional.\n\n### Cards\nSnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.\nSnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText) — One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).\nOverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.\nOverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline) — One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.\nContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.\nContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string) — A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.\nCompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.\nCompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button}) — A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.\nVisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.\nVisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string) — A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).\nText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nBoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nIconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\") — An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.\nImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number) — A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.\nImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean) — A full-width banner image above a bold title and optional subtitle. src must be a real image URL.\nMetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional +/- percentage trend and subtext, all on one line.\nMetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.\n- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.\n- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.\n- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.\n- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.\n- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.\n- VisualCardItem: image-first card with a BoldText body and optional Tag.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Stack(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Stack(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Stack(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root." - }, - { - "name": "openui-options", - "spec": { - "root": "Stack", - "components": { - "Card": { - "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)", - "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." - }, - "CardHeader": { - "signature": "CardHeader(title?: string, subtitle?: string)", - "description": "Header with optional title and subtitle" - }, - "TextContent": { - "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "MarkDownRenderer": { - "signature": "MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")", - "description": "Renders markdown text with optional container variant" - }, - "Callout": { - "signature": "Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)", - "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." - }, - "TextCallout": { - "signature": "TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)", - "description": "Text callout with variant, title, and description" - }, - "Image": { - "signature": "Image(alt: string, src?: string)", - "description": "Image with alt text and optional URL" - }, - "ImageBlock": { - "signature": "ImageBlock(src: string, alt?: string)", - "description": "Image block with loading state" - }, - "ImageGallery": { - "signature": "ImageGallery(images: {src: string, alt?: string, details?: string}[])", - "description": "Gallery grid of images with modal preview" - }, - "CodeBlock": { - "signature": "CodeBlock(language: string, codeString: string)", - "description": "Syntax-highlighted code block" - }, - "InlineHeader": { - "signature": "InlineHeader(heading: string, description?: string)", - "description": "Compact section heading with an optional one-line description, for use inside cards." - }, - "Table": { - "signature": "Table(columns: Col[])", - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", - "description": "Column definition — holds label + data array" - }, - "EditableTable": { - "signature": "EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])", - "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" - }, - "BarChart": { - "signature": "BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Vertical bars; use for comparing values across categories with one or more series" - }, - "LineChart": { - "signature": "LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Lines over categories; use for trends and continuous data over time" - }, - "AreaChart": { - "signature": "AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)", - "description": "Filled area under lines; use for cumulative totals or volume trends over time" - }, - "RadarChart": { - "signature": "RadarChart(labels: string[], series: Series[])", - "description": "Spider/web chart; use for comparing multiple variables across one or more entities" - }, - "HorizontalBarChart": { - "signature": "HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)", - "description": "Horizontal bars; prefer when category labels are long or for ranked lists" - }, - "Series": { - "signature": "Series(category: string, values: number[])", - "description": "One data series" - }, - "PieChart": { - "signature": "PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")", - "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" - }, - "RadialChart": { - "signature": "RadialChart(labels: string[], values: number[])", - "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" - }, - "SingleStackedBarChart": { - "signature": "SingleStackedBarChart(labels: string[], values: number[])", - "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" - }, - "Slice": { - "signature": "Slice(category: string, value: number)", - "description": "One slice with label and numeric value" - }, - "ScatterChart": { - "signature": "ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)", - "description": "X/Y scatter plot; use for correlations, distributions, and clustering" - }, - "ScatterSeries": { - "signature": "ScatterSeries(name: string, points: Point[])", - "description": "Named dataset" - }, - "Point": { - "signature": "Point(x: number, y: number, z?: number)", - "description": "Data point with numeric coordinates" - }, - "Form": { - "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", - "description": "Form container with fields and explicit action buttons" - }, - "FormControl": { - "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", - "description": "Field with label, input component, and optional hint text" - }, - "Label": { - "signature": "Label(text: string)", - "description": "Text label" - }, - "Input": { - "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "TextArea": { - "signature": "TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Select": { - "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", - "description": "" - }, - "SelectItem": { - "signature": "SelectItem(value: string, label: string)", - "description": "Option for Select" - }, - "DatePicker": { - "signature": "DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Slider": { - "signature": "Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "Numeric slider input; supports continuous and discrete (stepped) variants" - }, - "CheckBoxGroup": { - "signature": "CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)", - "description": "" - }, - "CheckBoxItem": { - "signature": "CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)", - "description": "" - }, - "RadioGroup": { - "signature": "RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "RadioItem": { - "signature": "RadioItem(label: string, description: string, value: string)", - "description": "" - }, - "SwitchGroup": { - "signature": "SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)", - "description": "Group of switch toggles" - }, - "SwitchItem": { - "signature": "SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)", - "description": "Individual switch toggle" - }, - "ChipItem": { - "signature": "ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)", - "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." - }, - "Chips": { - "signature": "Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", - "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." - }, - "OptionCard": { - "signature": "OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)", - "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." - }, - "OptionCards": { - "signature": "OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])", - "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." - }, - "Button": { - "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", - "description": "Clickable button" - }, - "Buttons": { - "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "IconButton": { - "signature": "IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")", - "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." - }, - "Stack": { - "signature": "Stack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)", - "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." - }, - "Tabs": { - "signature": "Tabs(items: TabItem[])", - "description": "Tabbed container" - }, - "TabItem": { - "signature": "TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])", - "description": "value is unique id, trigger is tab label, content is array of components" - }, - "Accordion": { - "signature": "Accordion(items: AccordionItem[])", - "description": "Collapsible sections" - }, - "AccordionItem": { - "signature": "AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])", - "description": "value is unique id, trigger is section title" - }, - "Steps": { - "signature": "Steps(items: StepsItem[])", - "description": "Step-by-step guide" - }, - "StepsItem": { - "signature": "StepsItem(title: string, details: string)", - "description": "title and details text for one step" - }, - "Carousel": { - "signature": "Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\")", - "description": "Horizontal scrollable carousel" - }, - "Separator": { - "signature": "Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)", - "description": "Visual divider between content sections" - }, - "TagBlock": { - "signature": "TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")", - "description": "tags is an array of strings; optional size sm | md | lg" - }, - "Tag": { - "signature": "Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")", - "description": "Styled tag/badge with optional Icon and variant" - }, - "Icon": { - "signature": "Icon(name: string, category?: string)", - "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." - }, - "EntityList": { - "signature": "EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})", - "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." - }, - "ListBlock": { - "signature": "ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")", - "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." - }, - "ListItem": { - "signature": "ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)", - "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." - }, - "Text": { - "signature": "Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", - "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "BoldText": { - "signature": "BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")", - "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "IconText": { - "signature": "IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")", - "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." - }, - "ImageText": { - "signature": "ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)", - "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." - }, - "ImageTextLarge": { - "signature": "ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)", - "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." - }, - "MetricIndicatorInline": { - "signature": "MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})", - "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." - }, - "MetricIndicatorWithStrikethrough": { - "signature": "MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})", - "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." - }, - "SnippetCardItem": { - "signature": "SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)", - "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." - }, - "SnippetCardBlock": { - "signature": "SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." - }, - "OverviewCardItem": { - "signature": "OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)", - "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." - }, - "OverviewCardBlock": { - "signature": "OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." - }, - "ContextCardItem": { - "signature": "ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)", - "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." - }, - "ContextCardBlock": { - "signature": "ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." - }, - "CompositeCardItem": { - "signature": "CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})", - "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." - }, - "CompositeCardBlock": { - "signature": "CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." - }, - "VisualCardItem": { - "signature": "VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)", - "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." - }, - "VisualCardBlock": { - "signature": "VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)", - "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." - }, - "Modal": { - "signature": "Modal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\")", - "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." - } - }, - "componentGroups": [ - { - "name": "Layout", - "components": [ - "Stack", - "Tabs", - "TabItem", - "Accordion", - "AccordionItem", - "Steps", - "StepsItem", - "Carousel", - "Separator", - "Modal" - ], - "notes": [ - "- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.", - "- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.", - "- Use nested Stacks when you need explicit rows/sections.", - "- Show/hide sections: $editId != \"\" ? Card([editForm]) : null", - "- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.", - "- Use Tabs for alternative views (chart types, data sections) — no $variable needed", - "- Shared filter across Tabs: same $days binding in Query args works across all TabItems" - ] - }, - { - "name": "Content", - "components": [ - "Card", - "CardHeader", - "TextContent", - "MarkDownRenderer", - "Callout", - "TextCallout", - "Image", - "ImageBlock", - "ImageGallery", - "CodeBlock", - "InlineHeader" - ], - "notes": [ - "- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).", - "- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.", - "- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null", - "- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])" - ] - }, - { - "name": "Tables", - "components": [ - "Table", - "Col", - "EditableTable" - ], - "notes": [ - "- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).", - "- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.", - "- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName", - "- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))", - "- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))", - "- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data", - "- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input", - "- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts", - "- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")" - ] - }, - { - "name": "Charts (2D)", - "components": [ - "BarChart", - "LineChart", - "AreaChart", - "RadarChart", - "HorizontalBarChart", - "Series" - ], - "notes": [ - "- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])", - "- Use Cards to wrap charts with CardHeader for titled sections", - "- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data", - "- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])" - ] - }, - { - "name": "Charts (1D)", - "components": [ - "PieChart", - "RadialChart", - "SingleStackedBarChart", - "Slice" - ], - "notes": [ - "- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:", - "- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`", - "- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`" - ] - }, - { - "name": "Charts (Scatter)", - "components": [ - "ScatterChart", - "ScatterSeries", - "Point" - ] - }, - { - "name": "Forms", - "components": [ - "Form", - "FormControl", - "Label", - "Input", - "TextArea", - "Select", - "SelectItem", - "DatePicker", - "Slider", - "CheckBoxGroup", - "CheckBoxItem", - "RadioGroup", - "RadioItem", - "SwitchGroup", - "SwitchItem", - "Chips", - "ChipItem", - "OptionCards", - "OptionCard" - ], - "notes": [ - "- Chips: compact single/multiple selection pills. Use ChipItem references for each option.", - "- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.", - "- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.", - "- NEVER nest Form inside Form — each Form should be a standalone container.", - "- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.", - "- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}", - "- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric", - "- The renderer shows error messages automatically — do NOT generate error text in the UI", - "- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField", - "- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal." - ] - }, - { - "name": "Buttons", - "components": [ - "Button", - "Buttons", - "IconButton" - ], - "notes": [ - "- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.", - "- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))" - ] - }, - { - "name": "Data Display", - "components": [ - "TagBlock", - "Tag", - "Icon", - "EntityList", - "ListBlock", - "ListItem" - ], - "notes": [ - "- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")", - "- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.", - "- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional." - ] - }, - { - "name": "Cards", - "components": [ - "SnippetCardBlock", - "SnippetCardItem", - "OverviewCardBlock", - "OverviewCardItem", - "ContextCardBlock", - "ContextCardItem", - "CompositeCardBlock", - "CompositeCardItem", - "VisualCardBlock", - "VisualCardItem", - "Text", - "BoldText", - "IconText", - "ImageText", - "ImageTextLarge", - "MetricIndicatorInline", - "MetricIndicatorWithStrikethrough" - ], - "notes": [ - "- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.", - "- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.", - "- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.", - "- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.", - "- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.", - "- VisualCardItem: image-first card with a BoldText body and optional Tag.", - "- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card." - ] - } - ], - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "Card": { - "$ref": "#/$defs/Card" - }, - "CardHeader": { - "$ref": "#/$defs/CardHeader" - }, - "TextContent": { - "$ref": "#/$defs/TextContent" - }, - "MarkDownRenderer": { - "$ref": "#/$defs/MarkDownRenderer" - }, - "Callout": { - "$ref": "#/$defs/Callout" - }, - "TextCallout": { - "$ref": "#/$defs/TextCallout" - }, - "Image": { - "$ref": "#/$defs/Image" - }, - "ImageBlock": { - "$ref": "#/$defs/ImageBlock" - }, - "ImageGallery": { - "$ref": "#/$defs/ImageGallery" - }, - "CodeBlock": { - "$ref": "#/$defs/CodeBlock" - }, - "InlineHeader": { - "$ref": "#/$defs/InlineHeader" - }, - "Table": { - "$ref": "#/$defs/Table" - }, - "Col": { - "$ref": "#/$defs/Col" - }, - "EditableTable": { - "$ref": "#/$defs/EditableTable" - }, - "BarChart": { - "$ref": "#/$defs/BarChart" - }, - "LineChart": { - "$ref": "#/$defs/LineChart" - }, - "AreaChart": { - "$ref": "#/$defs/AreaChart" - }, - "RadarChart": { - "$ref": "#/$defs/RadarChart" - }, - "HorizontalBarChart": { - "$ref": "#/$defs/HorizontalBarChart" - }, - "Series": { - "$ref": "#/$defs/Series" - }, - "PieChart": { - "$ref": "#/$defs/PieChart" - }, - "RadialChart": { - "$ref": "#/$defs/RadialChart" - }, - "SingleStackedBarChart": { - "$ref": "#/$defs/SingleStackedBarChart" - }, - "Slice": { - "$ref": "#/$defs/Slice" - }, - "ScatterChart": { - "$ref": "#/$defs/ScatterChart" - }, - "ScatterSeries": { - "$ref": "#/$defs/ScatterSeries" - }, - "Point": { - "$ref": "#/$defs/Point" - }, - "Form": { - "$ref": "#/$defs/Form" - }, - "FormControl": { - "$ref": "#/$defs/FormControl" - }, - "Label": { - "$ref": "#/$defs/Label" - }, - "Input": { - "$ref": "#/$defs/Input" - }, - "TextArea": { - "$ref": "#/$defs/TextArea" - }, - "Select": { - "$ref": "#/$defs/Select" - }, - "SelectItem": { - "$ref": "#/$defs/SelectItem" - }, - "DatePicker": { - "$ref": "#/$defs/DatePicker" - }, - "Slider": { - "$ref": "#/$defs/Slider" - }, - "CheckBoxGroup": { - "$ref": "#/$defs/CheckBoxGroup" - }, - "CheckBoxItem": { - "$ref": "#/$defs/CheckBoxItem" - }, - "RadioGroup": { - "$ref": "#/$defs/RadioGroup" - }, - "RadioItem": { - "$ref": "#/$defs/RadioItem" - }, - "SwitchGroup": { - "$ref": "#/$defs/SwitchGroup" - }, - "SwitchItem": { - "$ref": "#/$defs/SwitchItem" - }, - "ChipItem": { - "$ref": "#/$defs/ChipItem" - }, - "Chips": { - "$ref": "#/$defs/Chips" - }, - "OptionCard": { - "$ref": "#/$defs/OptionCard" - }, - "OptionCards": { - "$ref": "#/$defs/OptionCards" - }, - "Button": { - "$ref": "#/$defs/Button" - }, - "Buttons": { - "$ref": "#/$defs/Buttons" - }, - "IconButton": { - "$ref": "#/$defs/IconButton" - }, - "Stack": { - "$ref": "#/$defs/Stack" - }, - "Tabs": { - "$ref": "#/$defs/Tabs" - }, - "TabItem": { - "$ref": "#/$defs/TabItem" - }, - "Accordion": { - "$ref": "#/$defs/Accordion" - }, - "AccordionItem": { - "$ref": "#/$defs/AccordionItem" - }, - "Steps": { - "$ref": "#/$defs/Steps" - }, - "StepsItem": { - "$ref": "#/$defs/StepsItem" - }, - "Carousel": { - "$ref": "#/$defs/Carousel" - }, - "Separator": { - "$ref": "#/$defs/Separator" - }, - "TagBlock": { - "$ref": "#/$defs/TagBlock" - }, - "Tag": { - "$ref": "#/$defs/Tag" - }, - "Icon": { - "$ref": "#/$defs/Icon" - }, - "EntityList": { - "$ref": "#/$defs/EntityList" - }, - "ListBlock": { - "$ref": "#/$defs/ListBlock" - }, - "ListItem": { - "$ref": "#/$defs/ListItem" - }, - "Text": { - "$ref": "#/$defs/Text" - }, - "BoldText": { - "$ref": "#/$defs/BoldText" - }, - "IconText": { - "$ref": "#/$defs/IconText" - }, - "ImageText": { - "$ref": "#/$defs/ImageText" - }, - "ImageTextLarge": { - "$ref": "#/$defs/ImageTextLarge" - }, - "MetricIndicatorInline": { - "$ref": "#/$defs/MetricIndicatorInline" - }, - "MetricIndicatorWithStrikethrough": { - "$ref": "#/$defs/MetricIndicatorWithStrikethrough" - }, - "SnippetCardItem": { - "$ref": "#/$defs/SnippetCardItem" - }, - "SnippetCardBlock": { - "$ref": "#/$defs/SnippetCardBlock" - }, - "OverviewCardItem": { - "$ref": "#/$defs/OverviewCardItem" - }, - "OverviewCardBlock": { - "$ref": "#/$defs/OverviewCardBlock" - }, - "ContextCardItem": { - "$ref": "#/$defs/ContextCardItem" - }, - "ContextCardBlock": { - "$ref": "#/$defs/ContextCardBlock" - }, - "CompositeCardItem": { - "$ref": "#/$defs/CompositeCardItem" - }, - "CompositeCardBlock": { - "$ref": "#/$defs/CompositeCardBlock" - }, - "VisualCardItem": { - "$ref": "#/$defs/VisualCardItem" - }, - "VisualCardBlock": { - "$ref": "#/$defs/VisualCardBlock" - }, - "Modal": { - "$ref": "#/$defs/Modal" - } - }, - "required": [ - "Card", - "CardHeader", - "TextContent", - "MarkDownRenderer", - "Callout", - "TextCallout", - "Image", - "ImageBlock", - "ImageGallery", - "CodeBlock", - "InlineHeader", - "Table", - "Col", - "EditableTable", - "BarChart", - "LineChart", - "AreaChart", - "RadarChart", - "HorizontalBarChart", - "Series", - "PieChart", - "RadialChart", - "SingleStackedBarChart", - "Slice", - "ScatterChart", - "ScatterSeries", - "Point", - "Form", - "FormControl", - "Label", - "Input", - "TextArea", - "Select", - "SelectItem", - "DatePicker", - "Slider", - "CheckBoxGroup", - "CheckBoxItem", - "RadioGroup", - "RadioItem", - "SwitchGroup", - "SwitchItem", - "ChipItem", - "Chips", - "OptionCard", - "OptionCards", - "Button", - "Buttons", - "IconButton", - "Stack", - "Tabs", - "TabItem", - "Accordion", - "AccordionItem", - "Steps", - "StepsItem", - "Carousel", - "Separator", - "TagBlock", - "Tag", - "Icon", - "EntityList", - "ListBlock", - "ListItem", - "Text", - "BoldText", - "IconText", - "ImageText", - "ImageTextLarge", - "MetricIndicatorInline", - "MetricIndicatorWithStrikethrough", - "SnippetCardItem", - "SnippetCardBlock", - "OverviewCardItem", - "OverviewCardBlock", - "ContextCardItem", - "ContextCardBlock", - "CompositeCardItem", - "CompositeCardBlock", - "VisualCardItem", - "VisualCardBlock", - "Modal" - ], - "additionalProperties": false, - "$defs": { - "Card": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - }, - { - "$ref": "#/$defs/Tabs" - }, - { - "$ref": "#/$defs/Carousel" - }, - { - "$ref": "#/$defs/Stack" - } - ] - } - }, - "variant": { - "type": "string", - "enum": [ - "card", - "sunk", - "clear" - ] - }, - "direction": { - "type": "string", - "enum": [ - "row", - "column" - ] - }, - "gap": { - "type": "string", - "enum": [ - "none", - "xs", - "s", - "m", - "l", - "xl", - "2xl" - ] - }, - "align": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "stretch", - "baseline" - ] - }, - "justify": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "between", - "around", - "evenly" - ] - }, - "wrap": { - "type": "boolean" - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." - }, - "TextContent": { - "type": "object", - "properties": { - "text": { - "type": "string" - }, - "size": { - "type": "string", - "enum": [ - "small", - "default", - "large", - "small-heavy", - "large-heavy" - ] - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "MarkDownRenderer": { - "type": "object", - "properties": { - "textMarkdown": { - "type": "string" - }, - "variant": { - "type": "string", - "enum": [ - "clear", - "card", - "sunk" - ] - } - }, - "required": [ - "textMarkdown" - ], - "additionalProperties": false, - "description": "Renders markdown text with optional container variant" - }, - "CardHeader": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - } - }, - "additionalProperties": false, - "description": "Header with optional title and subtitle" - }, - "Callout": { - "type": "object", - "properties": { - "variant": { - "type": "string", - "enum": [ - "info", - "warning", - "error", - "success", - "neutral" - ] - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "visible": { - "type": "boolean" - } - }, - "required": [ - "variant", - "title", - "description" - ], - "additionalProperties": false, - "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." - }, - "TextCallout": { - "type": "object", - "properties": { - "variant": { - "type": "string", - "enum": [ - "neutral", - "info", - "warning", - "success", - "danger" - ] - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - } - }, - "additionalProperties": false, - "description": "Text callout with variant, title, and description" - }, - "CodeBlock": { - "type": "object", - "properties": { - "language": { - "type": "string" - }, - "codeString": { - "type": "string" - } - }, - "required": [ - "language", - "codeString" - ], - "additionalProperties": false, - "description": "Syntax-highlighted code block" - }, - "Image": { - "type": "object", - "properties": { - "alt": { - "type": "string" - }, - "src": { - "type": "string" - } - }, - "required": [ - "alt" - ], - "additionalProperties": false, - "description": "Image with alt text and optional URL" - }, - "ImageBlock": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - } - }, - "required": [ - "src" - ], - "additionalProperties": false, - "description": "Image block with loading state" - }, - "ImageGallery": { - "type": "object", - "properties": { - "images": { - "type": "array", - "items": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "details": { - "type": "string" - } - }, - "required": [ - "src" - ], - "additionalProperties": false - } - } - }, - "required": [ - "images" - ], - "additionalProperties": false, - "description": "Gallery grid of images with modal preview" - }, - "Separator": { - "type": "object", - "properties": { - "orientation": { - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - }, - "decorative": { - "type": "boolean" - } - }, - "additionalProperties": false, - "description": "Visual divider between content sections" - }, - "HorizontalBarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "grouped", - "stacked" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Horizontal bars; prefer when category labels are long or for ranked lists" - }, - "Series": { - "type": "object", - "properties": { - "category": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "category", - "values" - ], - "additionalProperties": false, - "description": "One data series" - }, - "RadarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Spider/web chart; use for comparing multiple variables across one or more entities" - }, - "PieChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - }, - "variant": { - "type": "string", - "enum": [ - "pie", - "donut" - ] - }, - "appearance": { - "type": "string", - "enum": [ - "circular", - "semiCircular" - ] - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" - }, - "RadialChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" - }, - "SingleStackedBarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" - }, - "ScatterChart": { - "type": "object", - "properties": { - "datasets": { - "type": "array", - "items": { - "$ref": "#/$defs/ScatterSeries" - } - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - } - }, - "required": [ - "datasets" - ], - "additionalProperties": false, - "description": "X/Y scatter plot; use for correlations, distributions, and clustering" - }, - "ScatterSeries": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "points": { - "type": "array", - "items": { - "$ref": "#/$defs/Point" - } - } - }, - "required": [ - "name", - "points" - ], - "additionalProperties": false, - "description": "Named dataset" - }, - "Point": { - "type": "object", - "properties": { - "x": { - "type": "number" - }, - "y": { - "type": "number" - }, - "z": { - "type": "number" - } - }, - "required": [ - "x", - "y" - ], - "additionalProperties": false, - "description": "Data point with numeric coordinates" - }, - "AreaChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "linear", - "natural", - "step" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Filled area under lines; use for cumulative totals or volume trends over time" - }, - "BarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "grouped", - "stacked" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Vertical bars; use for comparing values across categories with one or more series" - }, - "LineChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "linear", - "natural", - "step" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Lines over categories; use for trends and continuous data over time" - }, - "Table": { - "type": "object", - "properties": { - "columns": { - "type": "array", - "items": { - "$ref": "#/$defs/Col" - } - } - }, - "required": [ - "columns" - ], - "additionalProperties": false, - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "data": {}, - "type": { - "type": "string", - "enum": [ - "string", - "number", - "action" - ] - } - }, - "required": [ - "label", - "data" - ], - "additionalProperties": false, - "description": "Column definition — holds label + data array" - }, - "TagBlock": { - "type": "object", - "properties": { - "tags": { - "type": "array", - "items": { - "type": "string" - } - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "tags" - ], - "additionalProperties": false, - "description": "tags is an array of strings; optional size sm | md | lg" - }, - "Form": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "buttons": { - "$ref": "#/$defs/Buttons" - }, - "fields": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/FormControl" - } - } - }, - "required": [ - "name", - "buttons", - "fields" - ], - "additionalProperties": false, - "description": "Form container with fields and explicit action buttons" - }, - "Buttons": { - "type": "object", - "properties": { - "buttons": { - "type": "array", - "items": { - "$ref": "#/$defs/Button" - } - }, - "direction": { - "type": "string", - "enum": [ - "row", - "column" - ] - } - }, - "required": [ - "buttons" - ], - "additionalProperties": false, - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "Button": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "variant": { - "type": "string", - "enum": [ - "primary", - "secondary", - "tertiary" - ] - }, - "type": { - "type": "string", - "enum": [ - "normal", - "destructive" - ] - }, - "size": { - "type": "string", - "enum": [ - "extra-small", - "small", - "medium", - "large" - ] - } - }, - "required": [ - "label" - ], - "additionalProperties": false, - "description": "Clickable button" - }, - "FormControl": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "input": { - "anyOf": [ - { - "$ref": "#/$defs/Input" - }, - { - "$ref": "#/$defs/TextArea" - }, - { - "$ref": "#/$defs/Select" - }, - { - "$ref": "#/$defs/DatePicker" - }, - { - "$ref": "#/$defs/Slider" - }, - { - "$ref": "#/$defs/CheckBoxGroup" - }, - { - "$ref": "#/$defs/RadioGroup" - }, - { - "$ref": "#/$defs/Chips" - }, - { - "$ref": "#/$defs/OptionCards" - } - ] - }, - "hint": { - "type": "string" - } - }, - "required": [ - "label", - "input" - ], - "additionalProperties": false, - "description": "Field with label, input component, and optional hint text" - }, - "Input": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "placeholder": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "text", - "email", - "password", - "number", - "url" - ] - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "TextArea": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "placeholder": { - "type": "string" - }, - "rows": { - "type": "number" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "Select": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/SelectItem" - } - }, - "placeholder": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - }, - "size": { - "type": "string", - "enum": [ - "small", - "medium", - "large" - ] - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "SelectItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false, - "description": "Option for Select" - }, - "DatePicker": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "mode": { - "type": "string", - "enum": [ - "single", - "range" - ] - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": {} - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "Slider": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "variant": { - "type": "string", - "enum": [ - "continuous", - "discrete" - ] - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "step": { - "type": "number" - }, - "defaultValue": { - "type": "array", - "items": { - "type": "number" - } - }, - "label": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "name", - "variant", - "min", - "max" - ], - "additionalProperties": false, - "description": "Numeric slider input; supports continuous and discrete (stepped) variants" - }, - "CheckBoxGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/CheckBoxItem" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": { - "type": "boolean" - } - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "CheckBoxItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "defaultChecked": { - "type": "boolean" - } - }, - "required": [ - "label", - "description", - "name" - ], - "additionalProperties": false - }, - "RadioGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/RadioItem" - } - }, - "defaultValue": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "RadioItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "value": { - "type": "string" - } - }, - "required": [ - "label", - "description", - "value" - ], - "additionalProperties": false - }, - "Chips": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "type": { - "default": "multiple", - "type": "string", - "enum": [ - "single", - "multiple" - ] - }, - "items": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/ChipItem" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "defaultValue": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - } - }, - "required": [ - "name", - "type", - "items" - ], - "additionalProperties": false, - "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." - }, - "ChipItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "disabled": { - "type": "boolean" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false, - "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." - }, - "Icon": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "category": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false, - "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." - }, - "OptionCards": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "type": { - "default": "single", - "type": "string", - "enum": [ - "single", - "multiple" - ] - }, - "items": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/OptionCard" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "defaultValue": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - } - }, - "required": [ - "name", - "type", - "items" - ], - "additionalProperties": false, - "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." - }, - "OptionCard": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "topContent": { - "anyOf": [ - { - "$ref": "#/$defs/Icon" - }, - { - "$ref": "#/$defs/Image" - } - ] - }, - "disabled": { - "type": "boolean" - } - }, - "required": [ - "value", - "title" - ], - "additionalProperties": false, - "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." - }, - "IconButton": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "variant": { - "type": "string", - "enum": [ - "primary", - "secondary", - "tertiary" - ] - }, - "size": { - "type": "string", - "enum": [ - "extra-small", - "small", - "medium", - "large" - ] - }, - "shape": { - "type": "string", - "enum": [ - "square", - "circle" - ] - } - }, - "required": [ - "name", - "icon" - ], - "additionalProperties": false, - "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." - }, - "Steps": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/StepsItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Step-by-step guide" - }, - "StepsItem": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "details": { - "type": "string" - } - }, - "required": [ - "title", - "details" - ], - "additionalProperties": false, - "description": "title and details text for one step" - }, - "InlineHeader": { - "type": "object", - "properties": { - "heading": { - "type": "string" - }, - "description": { - "type": "string" - } - }, - "required": [ - "heading" - ], - "additionalProperties": false, - "description": "Compact section heading with an optional one-line description, for use inside cards." - }, - "EntityList": { - "type": "object", - "properties": { - "rows": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - } - }, - "size": { - "default": "default", - "type": "string", - "enum": [ - "small", - "default" - ] - }, - "header": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - }, - "footer": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - } - }, - "required": [ - "rows", - "size" - ], - "additionalProperties": false, - "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." - }, - "EditableTable": { - "type": "object", - "properties": { - "name": { - "default": "", - "type": "string" - }, - "columns": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "text", - "number", - "date-single", - "select", - "url" - ] - }, - "key": { - "default": "default", - "type": "string" - }, - "header": { - "default": "", - "type": "string" - }, - "width": { - "type": "number" - }, - "options": { - "type": "array", - "items": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false - } - } - }, - "required": [ - "type", - "key", - "header" - ], - "additionalProperties": false - } - }, - "data": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - } - } - }, - "required": [ - "id", - "values" - ], - "additionalProperties": false - } - } - }, - "required": [ - "name", - "columns", - "data" - ], - "additionalProperties": false, - "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" - }, - "SnippetCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/SnippetCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." - }, - "SnippetCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "lhs": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - } - ] - }, - "rhs": { - "anyOf": [ - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/BoldText" - } - ] - } - }, - "required": [ - "lhs" - ], - "additionalProperties": false, - "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." - }, - "IconText": { - "type": "object", - "properties": { - "icon": { - "$ref": "#/$defs/Icon" - }, - "iconVariant": { - "default": "neutral", - "type": "string", - "enum": [ - "neutral", - "info", - "success", - "warning", - "danger", - "inverted", - "filled", - "soft" - ] - }, - "iconSize": { - "default": "m", - "type": "string", - "enum": [ - "xs", - "s", - "m", - "l", - "xl", - "sm", - "md", - "lg" - ] - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - }, - "layout": { - "default": "horizontal", - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - } - }, - "required": [ - "icon", - "iconVariant", - "iconSize", - "title", - "bold", - "layout" - ], - "additionalProperties": false, - "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." - }, - "ImageText": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - }, - "layout": { - "default": "horizontal", - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - }, - "imageSize": { - "type": "number" - } - }, - "required": [ - "src", - "title", - "bold", - "layout" - ], - "additionalProperties": false, - "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." - }, - "Text": { - "type": "object", - "properties": { - "variant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - }, - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "subtextVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number", - "metric" - ] - }, - "size": { - "default": "sm", - "type": "string", - "enum": [ - "xs", - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "variant", - "value", - "subtextVariant", - "size" - ], - "additionalProperties": false, - "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "BoldText": { - "type": "object", - "properties": { - "variant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - }, - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "subtextVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number", - "metric" - ] - }, - "size": { - "default": "sm", - "type": "string", - "enum": [ - "xs", - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "variant", - "value", - "subtextVariant", - "size" - ], - "additionalProperties": false, - "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "OverviewCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/OverviewCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." - }, - "OverviewCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "top": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - }, - { - "$ref": "#/$defs/Text" - } - ] - }, - "bottom": { - "$ref": "#/$defs/MetricIndicatorInline" - } - }, - "required": [ - "top" - ], - "additionalProperties": false, - "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." - }, - "MetricIndicatorInline": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "trend": { - "type": "object", - "properties": { - "direction": { - "type": "string", - "enum": [ - "up", - "down" - ] - }, - "value": { - "type": "number" - } - }, - "required": [ - "direction", - "value" - ], - "additionalProperties": false - } - }, - "required": [ - "value" - ], - "additionalProperties": false, - "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." - }, - "ContextCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/ContextCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." - }, - "ContextCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "title": { - "anyOf": [ - { - "type": "string" - }, - { - "$ref": "#/$defs/Tag" - } - ] - }, - "body": { - "type": "string" - }, - "bgColor": { - "type": "string", - "enum": [ - "gray" - ] - }, - "bgImageSrc": { - "type": "string" - }, - "bgImageAlt": { - "type": "string" - } - }, - "required": [ - "title" - ], - "additionalProperties": false, - "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." - }, - "Tag": { - "type": "object", - "properties": { - "text": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - }, - "variant": { - "type": "string", - "enum": [ - "neutral", - "info", - "success", - "warning", - "danger" - ] - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Styled tag/badge with optional Icon and variant" - }, - "CompositeCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/CompositeCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." - }, - "CompositeCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "header": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - }, - { - "$ref": "#/$defs/ImageTextLarge" - }, - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/Image" - } - ] - }, - "body": { - "default": [], - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/BoldText" - }, - { - "$ref": "#/$defs/MetricIndicatorInline" - }, - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/ListBlock" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/EntityList" - } - ] - } - }, - "footer": { - "type": "object", - "properties": { - "price": { - "anyOf": [ - { - "$ref": "#/$defs/BoldText" - }, - { - "$ref": "#/$defs/MetricIndicatorWithStrikethrough" - } - ] - }, - "button": { - "$ref": "#/$defs/Button" - } - }, - "additionalProperties": false - } - }, - "required": [ - "body" - ], - "additionalProperties": false, - "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." - }, - "ImageTextLarge": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - } - }, - "required": [ - "src", - "title", - "bold" - ], - "additionalProperties": false, - "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." - }, - "ListBlock": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/ListItem" - } - }, - "variant": { - "type": "string", - "enum": [ - "number", - "image" - ] - }, - "size": { - "type": "string", - "enum": [ - "default", - "small" - ] - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." - }, - "ListItem": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "image": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - } - }, - "required": [ - "src", - "alt" - ], - "additionalProperties": false - }, - "actionLabel": { - "type": "string" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "title" - ], - "additionalProperties": false, - "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." - }, - "MetricIndicatorWithStrikethrough": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "previousValue": { - "type": "string" - }, - "trend": { - "type": "object", - "properties": { - "direction": { - "type": "string", - "enum": [ - "up", - "down" - ] - }, - "value": { - "type": "number" - } - }, - "required": [ - "direction", - "value" - ], - "additionalProperties": false - } - }, - "required": [ - "value" - ], - "additionalProperties": false, - "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." - }, - "VisualCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/VisualCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." - }, - "VisualCardItem": { - "type": "object", - "properties": { - "body": { - "$ref": "#/$defs/BoldText" - }, - "id": { - "type": "string" - }, - "bgImageSrc": { - "type": "string" - }, - "tag": { - "$ref": "#/$defs/Tag" - }, - "bgImageAlt": { - "type": "string" - } - }, - "required": [ - "body" - ], - "additionalProperties": false, - "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." - }, - "Tabs": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/TabItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Tabbed container" - }, - "TabItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "trigger": { - "type": "string" - }, - "content": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - } - }, - "required": [ - "value", - "trigger", - "content" - ], - "additionalProperties": false, - "description": "value is unique id, trigger is tab label, content is array of components" - }, - "Carousel": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - } - }, - "variant": { - "type": "string", - "enum": [ - "card", - "sunk" - ] - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Horizontal scrollable carousel" - }, - "Stack": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": {} - }, - "direction": { - "type": "string", - "enum": [ - "row", - "column" - ] - }, - "gap": { - "type": "string", - "enum": [ - "none", - "xs", - "s", - "m", - "l", - "xl", - "2xl" - ] - }, - "align": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "stretch", - "baseline" - ] - }, - "justify": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "between", - "around", - "evenly" - ] - }, - "wrap": { - "type": "boolean" - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." - }, - "Slice": { - "type": "object", - "properties": { - "category": { - "type": "string" - }, - "value": { - "type": "number" - } - }, - "required": [ - "category", - "value" - ], - "additionalProperties": false, - "description": "One slice with label and numeric value" - }, - "Label": { - "type": "object", - "properties": { - "text": { - "type": "string" - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Text label" - }, - "SwitchGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/SwitchItem" - } - }, - "variant": { - "type": "string", - "enum": [ - "clear", - "card", - "sunk" - ] - }, - "value": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": { - "type": "boolean" - } - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false, - "description": "Group of switch toggles" - }, - "SwitchItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "defaultChecked": { - "type": "boolean" - } - }, - "required": [ - "name" - ], - "additionalProperties": false, - "description": "Individual switch toggle" - }, - "Accordion": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/AccordionItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Collapsible sections" - }, - "AccordionItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "trigger": { - "type": "string" - }, - "content": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - } - }, - "required": [ - "value", - "trigger", - "content" - ], - "additionalProperties": false, - "description": "value is unique id, trigger is section title" - }, - "Modal": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "open": { - "type": "boolean" - }, - "children": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "title", - "children" - ], - "additionalProperties": false, - "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." - } - } - }, - "examples": [ - "Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]", - "Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])", - "Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])", - "Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]", - "Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")", - "Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])" - ], - "additionalRules": [ - "When asked about data, generate realistic/plausible data", - "For grid-like layouts, use Stack with direction \"row\" and wrap=true. Avoid justify=\"between\" unless you specifically want large gutters.", - "For forms, define one FormControl reference per field so controls can stream progressively.", - "For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).", - "Never nest Form inside Form.", - "Use @Reset($var1, $var2) after form submit to restore defaults — not @Set($var, \"\")", - "Multi-query refresh: Action([@Run(mutation), @Run(query1), @Run(query2), @Reset(...)])", - "$variables are reactive: changing via Select or @Set re-evaluates all Queries and expressions referencing them", - "Use existing components (Tabs, Accordion, Modal) before inventing ternary show/hide patterns", - "Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items; every item in a block must have the same structure.", - "Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicatorInline / MetricIndicatorWithStrikethrough are inline building blocks used INSIDE card items — do not place them directly in a Stack or Card.", - "EntityList size='small' (no header/footer) is only for use inside a CompositeCardItem body; use size='default' everywhere else.", - "Image URLs must be real (from a tool result or the user) — never invent or template an image URL.", - "Always pass a category to Icon — it enables a topical fallback when the exact icon name is unavailable.", - "EditableTable requires the consuming app to persist edits — use it only when the user or app explicitly asks for an editable table; default to Table for read-only data." - ] - }, - "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Stack(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Layout\nStack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean) — Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\".\nTabs(items: TabItem[]) — Tabbed container\nTabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[]) — value is unique id, trigger is tab label, content is array of components\nAccordion(items: AccordionItem[]) — Collapsible sections\nAccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[]) — value is unique id, trigger is section title\nSteps(items: StepsItem[]) — Step-by-step guide\nStepsItem(title: string, details: string) — title and details text for one step\nCarousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\") — Horizontal scrollable carousel\nSeparator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean) — Visual divider between content sections\nModal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\") — Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children.\n- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.\n- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.\n- Use nested Stacks when you need explicit rows/sections.\n- Show/hide sections: $editId != \"\" ? Card([editForm]) : null\n- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.\n- Use Tabs for alternative views (chart types, data sections) — no $variable needed\n- Shared filter across Tabs: same $days binding in Query args works across all TabItems\n\n### Content\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean) — Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts.\nCardHeader(title?: string, subtitle?: string) — Header with optional title and subtitle\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nMarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\") — Renders markdown text with optional container variant\nCallout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding) — Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.\nTextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string) — Text callout with variant, title, and description\nImage(alt: string, src?: string) — Image with alt text and optional URL\nImageBlock(src: string, alt?: string) — Image block with loading state\nImageGallery(images: {src: string, alt?: string, details?: string}[]) — Gallery grid of images with modal preview\nCodeBlock(language: string, codeString: string) — Syntax-highlighted code block\nInlineHeader(heading: string, description?: string) — Compact section heading with an optional one-line description, for use inside cards.\n- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).\n- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.\n- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null\n- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])\n\n### Tables\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\nEditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[]) — Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field\n- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).\n- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.\n- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName\n- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))\n- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))\n- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data\n- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input\n- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts\n- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")\n\n### Charts (2D)\nBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number) — Vertical bars; use for comparing values across categories with one or more series\nLineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Lines over categories; use for trends and continuous data over time\nAreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Filled area under lines; use for cumulative totals or volume trends over time\nRadarChart(labels: string[], series: Series[]) — Spider/web chart; use for comparing multiple variables across one or more entities\nHorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string) — Horizontal bars; prefer when category labels are long or for ranked lists\nSeries(category: string, values: number[]) — One data series\n- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])\n- Use Cards to wrap charts with CardHeader for titled sections\n- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data\n- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])\n\n### Charts (1D)\nPieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\") — Circular slices; use plucked arrays: PieChart(data.categories, data.values)\nRadialChart(labels: string[], values: number[]) — Radial bars; use plucked arrays: RadialChart(data.categories, data.values)\nSingleStackedBarChart(labels: string[], values: number[]) — Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)\nSlice(category: string, value: number) — One slice with label and numeric value\n- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:\n- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`\n- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`\n\n### Charts (Scatter)\nScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string) — X/Y scatter plot; use for correlations, distributions, and clustering\nScatterSeries(name: string, points: Point[]) — Named dataset\nPoint(x: number, y: number, z?: number) — Data point with numeric coordinates\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nLabel(text: string) — Text label\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nTextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nDatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSlider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding) — Numeric slider input; supports continuous and discrete (stepped) variants\nCheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)\nCheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)\nRadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nRadioItem(label: string, description: string, value: string)\nSwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>) — Group of switch toggles\nSwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean) — Individual switch toggle\nChips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.\nChipItem(value: string, label: string, icon?: Icon, disabled?: boolean) — A single selectable chip inside a Chips group, with a value, label and optional icon.\nOptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.\nOptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean) — A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.\n- Chips: compact single/multiple selection pills. Use ChipItem references for each option.\n- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.\n- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.\n- NEVER nest Form inside Form — each Form should be a standalone container.\n- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.\n- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}\n- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric\n- The renderer shows error messages automatically — do NOT generate error text in the UI\n- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField\n- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal.\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nIconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\") — Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.\n- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.\n- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))\n\n### Data Display\nTagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\") — tags is an array of strings; optional size sm | md | lg\nTag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\") — Styled tag/badge with optional Icon and variant\nIcon(name: string, category?: string) — A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.\nEntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}) — Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.\nListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\") — A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.\nListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression) — Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.\n- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")\n- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.\n- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional.\n\n### Cards\nSnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.\nSnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText) — One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).\nOverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.\nOverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline) — One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.\nContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.\nContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string) — A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.\nCompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.\nCompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button}) — A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.\nVisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.\nVisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string) — A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).\nText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nBoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nIconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\") — An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.\nImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number) — A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.\nImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean) — A full-width banner image above a bold title and optional subtitle. src must be a real image URL.\nMetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional +/- percentage trend and subtext, all on one line.\nMetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.\n- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.\n- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.\n- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.\n- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.\n- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.\n- VisualCardItem: image-first card with a BoldText body and optional Tag.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Stack(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Stack(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n\n## Examples\n\nExample 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]\n\nExample 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])\n\nExample 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])\n\nExample 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]\n\nExample 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")\n\nExample 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])\n\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Stack(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n\n- When asked about data, generate realistic/plausible data\n- For grid-like layouts, use Stack with direction \"row\" and wrap=true. Avoid justify=\"between\" unless you specifically want large gutters.\n- For forms, define one FormControl reference per field so controls can stream progressively.\n- For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).\n- Never nest Form inside Form.\n- Use @Reset($var1, $var2) after form submit to restore defaults — not @Set($var, \"\")\n- Multi-query refresh: Action([@Run(mutation), @Run(query1), @Run(query2), @Reset(...)])\n- $variables are reactive: changing via Select or @Set re-evaluates all Queries and expressions referencing them\n- Use existing components (Tabs, Accordion, Modal) before inventing ternary show/hide patterns\n- Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items; every item in a block must have the same structure.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicatorInline / MetricIndicatorWithStrikethrough are inline building blocks used INSIDE card items — do not place them directly in a Stack or Card.\n- EntityList size='small' (no header/footer) is only for use inside a CompositeCardItem body; use size='default' everywhere else.\n- Image URLs must be real (from a tool result or the user) — never invent or template an image URL.\n- Always pass a category to Icon — it enables a topical fallback when the exact icon name is unavailable.\n- EditableTable requires the consuming app to persist edits — use it only when the user or app explicitly asks for an editable table; default to Table for read-only data." - }, - { - "name": "slice-bindings", - "spec": { - "root": "Card", - "components": { - "Card": { - "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", - "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." - }, - "TextContent": { - "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "Button": { - "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", - "description": "Clickable button" - }, - "Buttons": { - "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "Form": { - "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", - "description": "Form container with fields and explicit action buttons" - }, - "FormControl": { - "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", - "description": "Field with label, input component, and optional hint text" - }, - "Input": { - "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Select": { - "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", - "description": "" - }, - "SelectItem": { - "signature": "SelectItem(value: string, label: string)", - "description": "Option for Select" - }, - "Table": { - "signature": "Table(columns: Col[])", - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", - "description": "Column definition — holds label + data array" - } - }, - "componentGroups": [ - { - "name": "Forms", - "components": [ - "Form", - "FormControl", - "Input", - "Select", - "SelectItem" - ], - "notes": [ - "- Forms note" - ] - }, - { - "name": "Buttons", - "components": [ - "Button", - "Buttons", - "Missing" - ] - } - ], - "bindings": true - }, - "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n8. Declare mutable state with `$varName = defaultValue`. Components marked with `$binding` can read/write these. Undeclared $variables are auto-created with null default.\n9. String concatenation: `\"text\" + $var + \"more\"`\n10. Dot member access: `query.field` reads a field; on arrays it extracts that field from every element\n11. Index access: `arr[0]`, `data[index]`\n12. Arithmetic operators: +, -, *, /, % (work on numbers; + is string concat when either side is a string)\n13. Comparison: ==, !=, >, <, >=, <=\n14. Logical: &&, ||, ! (prefix)\n15. Ternary: `condition ? valueIfTrue : valueIfFalse`\n16. Parentheses for grouping: `(a + b) * c`\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl, @Set, @Reset).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\n- Forms note\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Built-in Functions\n\nData functions prefixed with `@` to distinguish from components. These are the ONLY functions available — do NOT invent new ones.\nUse @-prefixed built-in functions (@Count, @Sum, @Avg, @Min, @Max, @Round) on Query results — do NOT hardcode computed values.\n\n@Count(array) → number — Returns array length\n@First(array) → element — Returns first element of array\n@Last(array) → element — Returns last element of array\n@Sum(numbers[]) → number — Sum of numeric array\n@Avg(numbers[]) → number — Average of numeric array\n@Min(numbers[]) → number — Minimum value in array\n@Max(numbers[]) → number — Maximum value in array\n@Sort(array, field, direction?) → sorted array — Sort array by field. Direction: \"asc\" (default) or \"desc\"\n@Filter(array, field, operator: \"==\" | \"!=\" | \">\" | \"<\" | \">=\" | \"<=\" | \"contains\", value) → filtered array — Filter array by field value\n@Round(number, decimals?) → number — Round to N decimal places (default 0)\n@Abs(number) → number — Absolute value\n@Floor(number) → number — Round down to nearest integer\n@Ceil(number) → number — Round up to nearest integer\n@Each(array, varName, template) — Evaluate template for each element. varName is the loop variable — use it ONLY inside the template expression (inline). Do NOT create a separate statement for the template.\n\nBuiltins compose — output of one is input to the next:\n`@Count(@Filter(data.rows, \"field\", \"==\", \"val\"))` for KPIs/chart values, `@Round(@Avg(data.rows.score), 1)`, `@Each(data.rows, \"item\", Comp(item.field))` for per-item rendering.\nArray pluck: `data.rows.field` extracts a field from every row → use with @Sum, @Avg, charts, tables.\n\nIMPORTANT @Each rule: The loop variable (e.g. \"item\") is ONLY available inside the @Each template expression. Always inline the template — do NOT extract it to a separate statement.\nCORRECT: `Col(\"Actions\", @Each(rows, \"t\", Button(\"Edit\", Action([@Set($id, t.id)]))))`\nWRONG: `myBtn = Button(\"Edit\", Action([@Set($id, t.id)]))` then `Col(\"Actions\", @Each(rows, \"t\", myBtn))` — t is undefined in myBtn.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n- @Set($variable, value) — Set a $variable to a specific value\n- @Reset($var1, $var2, ...) — Reset $variables to their declared defaults (e.g. @Reset($title, $priority) restores $title=\"\" and $priority=\"medium\")\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. $variable declarations — state ready for bindings\n3. Query statements — defaults resolve immediately so components render with data\n4. Component definitions — fill in with data already available\n5. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n3. Every $binding appears in at least one component or expression." - }, - { - "name": "slice-tools", - "spec": { - "root": "Card", - "components": { - "Card": { - "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", - "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." - }, - "TextContent": { - "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "Button": { - "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", - "description": "Clickable button" - }, - "Buttons": { - "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "Form": { - "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", - "description": "Form container with fields and explicit action buttons" - }, - "FormControl": { - "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", - "description": "Field with label, input component, and optional hint text" - }, - "Input": { - "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Select": { - "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", - "description": "" - }, - "SelectItem": { - "signature": "SelectItem(value: string, label: string)", - "description": "Option for Select" - }, - "Table": { - "signature": "Table(columns: Col[])", - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", - "description": "Column definition — holds label + data array" - } - }, - "componentGroups": [ - { - "name": "Forms", - "components": [ - "Form", - "FormControl", - "Input", - "Select", - "SelectItem" - ], - "notes": [ - "- Forms note" - ] - }, - { - "name": "Buttons", - "components": [ - "Button", - "Buttons", - "Missing" - ] - } - ], - "tools": [ - "search_docs", - { - "name": "list_tickets", - "description": "Open support tickets", - "inputSchema": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "open", - "closed" - ] - }, - "limit": { - "type": "number" - } - }, - "required": [ - "status" - ] - }, - "outputSchema": { - "type": "object", - "properties": { - "rows": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - } - } - } - }, - "total": { - "type": "integer" - } - } - } - }, - { - "name": "ping", - "inputSchema": {} - } - ], - "toolExamples": [ - "x = Query(\"list_tickets\", {status: \"open\"}, {rows: []})" - ] - }, - "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n8. Declare mutable state with `$varName = defaultValue`. Components marked with `$binding` can read/write these. Undeclared $variables are auto-created with null default.\n9. String concatenation: `\"text\" + $var + \"more\"`\n10. Dot member access: `query.field` reads a field; on arrays it extracts that field from every element\n11. Index access: `arr[0]`, `data[index]`\n12. Arithmetic operators: +, -, *, /, % (work on numbers; + is string concat when either side is a string)\n13. Comparison: ==, !=, >, <, >=, <=\n14. Logical: &&, ||, ! (prefix)\n15. Ternary: `condition ? valueIfTrue : valueIfFalse`\n16. Parentheses for grouping: `(a + b) * c`\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@Run, @ToAssistant, @OpenUrl, @Set, @Reset).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\n- Forms note\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Built-in Functions\n\nData functions prefixed with `@` to distinguish from components. These are the ONLY functions available — do NOT invent new ones.\nUse @-prefixed built-in functions (@Count, @Sum, @Avg, @Min, @Max, @Round) on Query results — do NOT hardcode computed values.\n\n@Count(array) → number — Returns array length\n@First(array) → element — Returns first element of array\n@Last(array) → element — Returns last element of array\n@Sum(numbers[]) → number — Sum of numeric array\n@Avg(numbers[]) → number — Average of numeric array\n@Min(numbers[]) → number — Minimum value in array\n@Max(numbers[]) → number — Maximum value in array\n@Sort(array, field, direction?) → sorted array — Sort array by field. Direction: \"asc\" (default) or \"desc\"\n@Filter(array, field, operator: \"==\" | \"!=\" | \">\" | \"<\" | \">=\" | \"<=\" | \"contains\", value) → filtered array — Filter array by field value\n@Round(number, decimals?) → number — Round to N decimal places (default 0)\n@Abs(number) → number — Absolute value\n@Floor(number) → number — Round down to nearest integer\n@Ceil(number) → number — Round up to nearest integer\n@Each(array, varName, template) — Evaluate template for each element. varName is the loop variable — use it ONLY inside the template expression (inline). Do NOT create a separate statement for the template.\n\nBuiltins compose — output of one is input to the next:\n`@Count(@Filter(data.rows, \"field\", \"==\", \"val\"))` for KPIs/chart values, `@Round(@Avg(data.rows.score), 1)`, `@Each(data.rows, \"item\", Comp(item.field))` for per-item rendering.\nArray pluck: `data.rows.field` extracts a field from every row → use with @Sum, @Avg, charts, tables.\n\nIMPORTANT @Each rule: The loop variable (e.g. \"item\") is ONLY available inside the @Each template expression. Always inline the template — do NOT extract it to a separate statement.\nCORRECT: `Col(\"Actions\", @Each(rows, \"t\", Button(\"Edit\", Action([@Set($id, t.id)]))))`\nWRONG: `myBtn = Button(\"Edit\", Action([@Set($id, t.id)]))` then `Col(\"Actions\", @Each(rows, \"t\", myBtn))` — t is undefined in myBtn.\n\n## Query — Live Data Fetching\n\nFetch data from available tools. Returns defaults instantly, swaps in real data when it arrives.\n\n```\nmetrics = Query(\"tool_name\", {arg1: value, arg2: $binding}, {defaultField: 0, defaultData: []}, refreshInterval?)\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (may reference $bindings — re-fetches automatically on change)\n- Third arg: default data (rendered immediately before fetch resolves)\n- Fourth arg (optional): refresh interval in seconds (e.g. 30 for auto-refresh every 30s)\n- Use dot access on results: metrics.totalEvents, metrics.data.day (array pluck)\n- Query results must use regular identifiers: `metrics = Query(...)`, NOT `$metrics = Query(...)`\n- Manual refresh: `Button(\"Refresh\", Action([@Run(query1), @Run(query2)]), \"secondary\")` — re-fetches the listed queries\n- Refresh all queries: create Action with @Run for each query\n\n## Mutation — Write Operations\n\nExecute state-changing tool calls (create, update, delete). Unlike Query (auto-fetches on render), Mutation fires only on button click via Action.\n\n```\nresult = Mutation(\"tool_name\", {arg1: $binding, arg2: \"value\"})\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (evaluated with current $binding values at click time)\n- result.status: \"idle\" | \"loading\" | \"success\" | \"error\"\n- result.data: tool response on success\n- result.error: error message on failure\n- Mutation results use regular identifiers: `result = Mutation(...)`, NOT `$result`\n- Show loading state: `result.status == \"loading\" ? TextContent(\"Saving...\") : null`\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @Run(queryOrMutationRef) — Execute a Mutation or re-fetch a Query (ref must be a declared Query/Mutation)\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n- @Set($variable, value) — Set a $variable to a specific value\n- @Reset($var1, $var2, ...) — Reset $variables to their declared defaults (e.g. @Reset($title, $priority) restores $title=\"\" and $priority=\"medium\")\n\nExample — mutation + refresh + reset (PREFERRED pattern):\n```\n$binding = \"default\"\nresult = Mutation(\"tool_name\", {field: $binding})\ndata = Query(\"tool_name\", {}, {rows: []})\nonSubmit = Action([@Run(result), @Run(data), @Reset($binding)])\n```\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n- If a @Run(mutation) step fails, remaining steps are skipped (halt on failure)\n- @Run(queryRef) re-fetches the query (fire-and-forget, cannot fail)\n\n## Interactive Filters\n\nTo let the user filter data with a dropdown:\n1. Declare a $variable with a default: `$dateRange = \"14\"`\n2. Create a Select with name, items, and binding: `Select(\"dateRange\", [SelectItem(\"7\", \"Last 7 days\"), ...], null, null, $dateRange)`\n3. Wrap in FormControl for a label: `FormControl(\"Date Range\", Select(...))`\n4. Pass $dateRange in Query args: `Query(\"tool\", {dateRange: $dateRange}, {defaults})`\n5. When the user changes the Select, $dateRange updates and the Query automatically re-fetches\n\nFILTER WIRING RULE: If a $binding filter is visible in the UI, EVERY relevant Query MUST reference that $binding in its args. Never show a filter dropdown while hardcoding the query args.\n\nRules for $variables:\n- $variables hold simple values (strings or numbers), NOT arrays or objects\n- $variables must be bound to a Select/Input component via the value argument (last positional arg) to be interactive\n- Queries must use regular identifiers (NOT $variables): `metrics = Query(...)` not `$metrics = Query(...)`\n- **Auto-declare**: You do NOT need to explicitly declare $variables. If you use `$foo` without declaring it, the parser auto-creates `$foo = null`. You can still declare explicitly to set a default: `$days = \"14\"`\n\n## Forms\n\nSimple form — no $bindings needed. Field values are managed internally by the Form via the name prop:\n```\ncontactForm = Form(\"contact\", submitBtn, [nameField, emailField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", {required: true}))\nemailField = FormControl(\"Email\", Input(\"email\", \"your@email.com\", \"email\", {required: true, email: true}))\nsubmitBtn = Button(\"Submit\")\n```\n\nUse $bindings when you need to read field values elsewhere (in Action context, Query args, or conditionals). They are auto-declared:\n```\n$role = \"engineer\"\ncontactForm = Form(\"contact\", submitBtn, [nameField, emailField, roleField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Enter your name\", \"text\", {required: true}, $name))\nemailField = FormControl(\"Email\", Input(\"email\", \"Enter your email\", \"email\", {required: true, email: true}, $email))\nroleField = FormControl(\"Role\", Select(\"role\", [SelectItem(\"engineer\", \"Engineer\"), SelectItem(\"designer\", \"Designer\"), SelectItem(\"pm\", \"PM\")], null, {required: true}, $role))\nsubmitBtn = Button(\"Submit\")\n```\n\nFor form + mutation patterns (create, refresh, reset), see the Action section example above.\n\nIMPORTANT: Always add validation rules to form fields used with Mutations. Use OBJECT syntax: {required: true, email: true, minLength: 8}. The renderer shows error messages automatically and blocks submit when validation fails.\n\n## Data Workflow\n\nWhen tools are available, follow this workflow:\n1. FIRST: Call the most relevant tool to inspect the real data shape before generating code\n2. Use Query() for READ operations (data that should stay live) — NEVER hardcode tool results as literal arrays or objects\n3. Use Mutation() for WRITE operations (create, update, delete) — triggered by button clicks via Action([@Run(mutationRef)])\n4. Use the real data from step 1 as condensed Query defaults (3-5 rows) so the UI renders immediately\n5. Use @-prefixed builtins (@Count, @Filter, @Sort, @Sum) on Query results for KPIs and aggregations — the runtime evaluates these live on every refresh\n6. Hardcoded arrays are ONLY for static display data (labels, options) where no tool exists\n\nWRONG — you called a tool and got data back, but you inlined the results:\n```\nopenCount = 2\nitem1 = SomeComp(\"first item title\")\nitem2 = SomeComp(\"second item title\")\nlist = SomeList([item1, item2])\nchart = SomeChart([\"A\", \"B\"], [12, 8])\n```\nThis is static — it shows stale data and won't update. Creating item1, item2, item3... manually is ALWAYS wrong when a tool exists.\n\nRIGHT — use Query() for live data, Mutation() for writes, @builtins to derive values:\n```\ndata = Query(\"tool_name\", {}, {rows: []})\nopenCount = @Count(@Filter(data.rows, \"field\", \"==\", \"value\"))\nlist = @Each(data.rows, \"item\", SomeComp(item.title, item.field))\ncreateResult = Mutation(\"create_tool\", {title: $title})\nsubmitBtn = Button(\"Create\", Action([@Run(createResult), @Run(data), @Reset($title)]))\n```\nEverything derives from the Query — when data refreshes, the entire dashboard updates automatically.\n\n## Available Tools\n\nUse these with Query() for read operations or Mutation() for write operations. The LLM decides which is appropriate based on the tool's purpose.\n\n- search_docs\n- list_tickets(status: \"open\" | \"closed\", limit?: number) → {rows?: {id?: string}[], total?: number}\n Open support tickets\n- ping()\n\n### Default values for Query results\n\nUse these shapes as minimal Query defaults:\n- list_tickets: `{\"rows\":[],\"total\":0}`\n\nCRITICAL: Use ONLY the tools listed above in Query() and Mutation() calls. Do NOT invent or guess tool names. If the user asks for functionality that doesn't match any available tool, use realistic mock data instead of fabricating a tool call.\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. $variable declarations — state ready for bindings\n3. Query statements — defaults resolve immediately so components render with data\n4. Component definitions — fill in with data already available\n5. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n\n## Examples\n\nx = Query(\"list_tickets\", {status: \"open\"}, {rows: []})\n\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n3. Every Query result is referenced by at least one component.\n4. Every $binding appears in at least one component or expression.\n5. Every visible filter $binding appears in at least one Query args object." - }, - { - "name": "slice-tools-no-bindings", - "spec": { - "root": "Card", - "components": { - "Card": { - "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", - "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." - }, - "TextContent": { - "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "Button": { - "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", - "description": "Clickable button" - }, - "Buttons": { - "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "Form": { - "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", - "description": "Form container with fields and explicit action buttons" - }, - "FormControl": { - "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", - "description": "Field with label, input component, and optional hint text" - }, - "Input": { - "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Select": { - "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", - "description": "" - }, - "SelectItem": { - "signature": "SelectItem(value: string, label: string)", - "description": "Option for Select" - }, - "Table": { - "signature": "Table(columns: Col[])", - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", - "description": "Column definition — holds label + data array" - } - }, - "componentGroups": [ - { - "name": "Forms", - "components": [ - "Form", - "FormControl", - "Input", - "Select", - "SelectItem" - ], - "notes": [ - "- Forms note" - ] - }, - { - "name": "Buttons", - "components": [ - "Button", - "Buttons", - "Missing" - ] - } - ], - "tools": [ - "search_docs", - { - "name": "list_tickets", - "description": "Open support tickets", - "inputSchema": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "open", - "closed" - ] - }, - "limit": { - "type": "number" - } - }, - "required": [ - "status" - ] - }, - "outputSchema": { - "type": "object", - "properties": { - "rows": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - } - } - } - }, - "total": { - "type": "integer" - } - } - } - }, - { - "name": "ping", - "inputSchema": {} - } - ], - "bindings": false - }, - "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n8. String concatenation: `\"text\" + $var + \"more\"`\n9. Dot member access: `query.field` reads a field; on arrays it extracts that field from every element\n10. Index access: `arr[0]`, `data[index]`\n11. Arithmetic operators: +, -, *, /, % (work on numbers; + is string concat when either side is a string)\n12. Comparison: ==, !=, >, <, >=, <=\n13. Logical: &&, ||, ! (prefix)\n14. Ternary: `condition ? valueIfTrue : valueIfFalse`\n15. Parentheses for grouping: `(a + b) * c`\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@Run, @ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\n- Forms note\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Built-in Functions\n\nData functions prefixed with `@` to distinguish from components. These are the ONLY functions available — do NOT invent new ones.\nUse @-prefixed built-in functions (@Count, @Sum, @Avg, @Min, @Max, @Round) on Query results — do NOT hardcode computed values.\n\n@Count(array) → number — Returns array length\n@First(array) → element — Returns first element of array\n@Last(array) → element — Returns last element of array\n@Sum(numbers[]) → number — Sum of numeric array\n@Avg(numbers[]) → number — Average of numeric array\n@Min(numbers[]) → number — Minimum value in array\n@Max(numbers[]) → number — Maximum value in array\n@Sort(array, field, direction?) → sorted array — Sort array by field. Direction: \"asc\" (default) or \"desc\"\n@Filter(array, field, operator: \"==\" | \"!=\" | \">\" | \"<\" | \">=\" | \"<=\" | \"contains\", value) → filtered array — Filter array by field value\n@Round(number, decimals?) → number — Round to N decimal places (default 0)\n@Abs(number) → number — Absolute value\n@Floor(number) → number — Round down to nearest integer\n@Ceil(number) → number — Round up to nearest integer\n@Each(array, varName, template) — Evaluate template for each element. varName is the loop variable — use it ONLY inside the template expression (inline). Do NOT create a separate statement for the template.\n\nBuiltins compose — output of one is input to the next:\n`@Count(@Filter(data.rows, \"field\", \"==\", \"val\"))` for KPIs/chart values, `@Round(@Avg(data.rows.score), 1)`, `@Each(data.rows, \"item\", Comp(item.field))` for per-item rendering.\nArray pluck: `data.rows.field` extracts a field from every row → use with @Sum, @Avg, charts, tables.\n\nIMPORTANT @Each rule: The loop variable (e.g. \"item\") is ONLY available inside the @Each template expression. Always inline the template — do NOT extract it to a separate statement.\nCORRECT: `Col(\"Actions\", @Each(rows, \"t\", Button(\"Edit\", Action([@Set($id, t.id)]))))`\nWRONG: `myBtn = Button(\"Edit\", Action([@Set($id, t.id)]))` then `Col(\"Actions\", @Each(rows, \"t\", myBtn))` — t is undefined in myBtn.\n\n## Query — Live Data Fetching\n\nFetch data from available tools. Returns defaults instantly, swaps in real data when it arrives.\n\n```\nmetrics = Query(\"tool_name\", {arg1: value, arg2: $binding}, {defaultField: 0, defaultData: []}, refreshInterval?)\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (may reference $bindings — re-fetches automatically on change)\n- Third arg: default data (rendered immediately before fetch resolves)\n- Fourth arg (optional): refresh interval in seconds (e.g. 30 for auto-refresh every 30s)\n- Use dot access on results: metrics.totalEvents, metrics.data.day (array pluck)\n- Query results must use regular identifiers: `metrics = Query(...)`, NOT `$metrics = Query(...)`\n- Manual refresh: `Button(\"Refresh\", Action([@Run(query1), @Run(query2)]), \"secondary\")` — re-fetches the listed queries\n- Refresh all queries: create Action with @Run for each query\n\n## Mutation — Write Operations\n\nExecute state-changing tool calls (create, update, delete). Unlike Query (auto-fetches on render), Mutation fires only on button click via Action.\n\n```\nresult = Mutation(\"tool_name\", {arg1: $binding, arg2: \"value\"})\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (evaluated with current $binding values at click time)\n- result.status: \"idle\" | \"loading\" | \"success\" | \"error\"\n- result.data: tool response on success\n- result.error: error message on failure\n- Mutation results use regular identifiers: `result = Mutation(...)`, NOT `$result`\n- Show loading state: `result.status == \"loading\" ? TextContent(\"Saving...\") : null`\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @Run(queryOrMutationRef) — Execute a Mutation or re-fetch a Query (ref must be a declared Query/Mutation)\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — mutation + refresh + reset (PREFERRED pattern):\n```\n$binding = \"default\"\nresult = Mutation(\"tool_name\", {field: $binding})\ndata = Query(\"tool_name\", {}, {rows: []})\nonSubmit = Action([@Run(result), @Run(data), @Reset($binding)])\n```\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n- If a @Run(mutation) step fails, remaining steps are skipped (halt on failure)\n- @Run(queryRef) re-fetches the query (fire-and-forget, cannot fail)\n\n## Data Workflow\n\nWhen tools are available, follow this workflow:\n1. FIRST: Call the most relevant tool to inspect the real data shape before generating code\n2. Use Query() for READ operations (data that should stay live) — NEVER hardcode tool results as literal arrays or objects\n3. Use Mutation() for WRITE operations (create, update, delete) — triggered by button clicks via Action([@Run(mutationRef)])\n4. Use the real data from step 1 as condensed Query defaults (3-5 rows) so the UI renders immediately\n5. Use @-prefixed builtins (@Count, @Filter, @Sort, @Sum) on Query results for KPIs and aggregations — the runtime evaluates these live on every refresh\n6. Hardcoded arrays are ONLY for static display data (labels, options) where no tool exists\n\nWRONG — you called a tool and got data back, but you inlined the results:\n```\nopenCount = 2\nitem1 = SomeComp(\"first item title\")\nitem2 = SomeComp(\"second item title\")\nlist = SomeList([item1, item2])\nchart = SomeChart([\"A\", \"B\"], [12, 8])\n```\nThis is static — it shows stale data and won't update. Creating item1, item2, item3... manually is ALWAYS wrong when a tool exists.\n\nRIGHT — use Query() for live data, Mutation() for writes, @builtins to derive values:\n```\ndata = Query(\"tool_name\", {}, {rows: []})\nopenCount = @Count(@Filter(data.rows, \"field\", \"==\", \"value\"))\nlist = @Each(data.rows, \"item\", SomeComp(item.title, item.field))\ncreateResult = Mutation(\"create_tool\", {title: $title})\nsubmitBtn = Button(\"Create\", Action([@Run(createResult), @Run(data), @Reset($title)]))\n```\nEverything derives from the Query — when data refreshes, the entire dashboard updates automatically.\n\n## Available Tools\n\nUse these with Query() for read operations or Mutation() for write operations. The LLM decides which is appropriate based on the tool's purpose.\n\n- search_docs\n- list_tickets(status: \"open\" | \"closed\", limit?: number) → {rows?: {id?: string}[], total?: number}\n Open support tickets\n- ping()\n\n### Default values for Query results\n\nUse these shapes as minimal Query defaults:\n- list_tickets: `{\"rows\":[],\"total\":0}`\n\nCRITICAL: Use ONLY the tools listed above in Query() and Mutation() calls. Do NOT invent or guess tool names. If the user asks for functionality that doesn't match any available tool, use realistic mock data instead of fabricating a tool call.\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. $variable declarations — state ready for bindings\n3. Query statements — defaults resolve immediately so components render with data\n4. Component definitions — fill in with data already available\n5. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n3. Every Query result is referenced by at least one component." - }, - { - "name": "slice-modes", - "spec": { - "root": "Card", - "components": { - "Card": { - "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", - "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." - }, - "TextContent": { - "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "Button": { - "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", - "description": "Clickable button" - }, - "Buttons": { - "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "Form": { - "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", - "description": "Form container with fields and explicit action buttons" - }, - "FormControl": { - "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", - "description": "Field with label, input component, and optional hint text" - }, - "Input": { - "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Select": { - "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", - "description": "" - }, - "SelectItem": { - "signature": "SelectItem(value: string, label: string)", - "description": "Option for Select" - }, - "Table": { - "signature": "Table(columns: Col[])", - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", - "description": "Column definition — holds label + data array" - } - }, - "componentGroups": [ - { - "name": "Forms", - "components": [ - "Form", - "FormControl", - "Input", - "Select", - "SelectItem" - ], - "notes": [ - "- Forms note" - ] - }, - { - "name": "Buttons", - "components": [ - "Button", - "Buttons", - "Missing" - ] - } - ], - "editMode": true, - "inlineMode": true, - "preamble": "Custom preamble.", - "additionalRules": [ - "Be brief" - ], - "examples": [ - "a = 1" - ] - }, - "expected": "Custom preamble.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\n- Forms note\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n\n## Examples\n\na = 1\n\n\n## Edit Mode\n\nThe runtime merges by statement name: same name = replace, new name = append.\nOutput ONLY statements that changed or are new. Everything else is kept automatically.\n\n### Delete\nTo remove a component, re-declare its parent without that component in the parent's children array. The removed component and any statements only it referenced are automatically garbage-collected.\n\n### Patch size guide\n- Changing a title or label: 1 statement\n- Adding a component: 2-3 statements (the new component + parent update)\n- Removing a component: 1 statement (re-declare parent without the removed child)\n- Adding a filter + wiring to query: 3-5 statements\n- Restructuring into tabs: 5-10 statements\n\n### Rules\n- Reuse existing statement names exactly — do not rename\n- Do NOT re-emit unchanged statements — the runtime keeps them\n- A typical edit patch is 1-10 statements, not 20+\n- If the existing code already satisfies the request, output only the root statement\n- NEVER output the entire program as a patch. Only output what actually changes\n- If you are about to output more than 10 statements, reconsider — most edits need fewer\n\n## Inline Mode\n\nYou are in inline mode. You can respond in two ways:\n\n### 1. Code response (when the user wants to CREATE or CHANGE the UI)\nWrap openui-lang code in triple-backtick fences. You can include explanatory text before/after:\n\nHere's your dashboard:\n\n```openui-lang\nroot = RootComp([header, content])\nheader = SomeHeader(\"Title\")\ncontent = SomeContent(\"Hello world\")\n```\n\nI created a simple layout with a header.\n\n### 2. Text-only response (when the user asks a QUESTION)\nIf the user asks \"what is this?\", \"explain the chart\", \"how does this work\", etc. — respond with plain text. Do NOT output any openui-lang code. The existing dashboard stays unchanged.\n\n### Rules\n- When the user asks for changes, output ONLY the changed/new statements in a fenced block\n- When the user asks a question, respond with text only — NO code. The dashboard stays unchanged.\n- The parser extracts code from fences automatically. Text outside fences is shown as chat.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n\n- Be brief" - }, - { - "name": "slice-no-groups", - "spec": { - "root": "Card", - "components": { - "Card": { - "signature": "Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])", - "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." - }, - "TextContent": { - "signature": "TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")", - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "Button": { - "signature": "Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")", - "description": "Clickable button" - }, - "Buttons": { - "signature": "Buttons(buttons: Button[], direction?: \"row\" | \"column\")", - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "Form": { - "signature": "Form(name: string, buttons: Buttons, fields?: FormControl[])", - "description": "Form container with fields and explicit action buttons" - }, - "FormControl": { - "signature": "FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)", - "description": "Field with label, input component, and optional hint text" - }, - "Input": { - "signature": "Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)", - "description": "" - }, - "Select": { - "signature": "Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")", - "description": "" - }, - "SelectItem": { - "signature": "SelectItem(value: string, label: string)", - "description": "Option for Select" - }, - "Table": { - "signature": "Table(columns: Col[])", - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "signature": "Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")", - "description": "Column definition — holds label + data array" - } - } - }, - "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root." - }, - { - "name": "small-no-root", - "spec": { - "components": { - "Box": { - "signature": "Box(children: (Text | Box)[])", - "description": "A box" - }, - "Text": { - "signature": "Text(value: string, tone?: \"a\" | \"b\")" - } - } - }, - "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Root(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\n\nBox(children: (Text | Box)[]) — A box\nText(value: string, tone?: \"a\" | \"b\")\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Root(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Root(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Root(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root." - }, - { - "name": "small-tools-only", - "spec": { - "components": { - "Box": { - "signature": "Box(children: (Text | Box)[])", - "description": "A box" - }, - "Text": { - "signature": "Text(value: string, tone?: \"a\" | \"b\")" - } - }, - "toolCalls": true, - "bindings": false - }, - "expected": "You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Root(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n8. String concatenation: `\"text\" + $var + \"more\"`\n9. Dot member access: `query.field` reads a field; on arrays it extracts that field from every element\n10. Index access: `arr[0]`, `data[index]`\n11. Arithmetic operators: +, -, *, /, % (work on numbers; + is string concat when either side is a string)\n12. Comparison: ==, !=, >, <, >=, <=\n13. Logical: &&, ||, ! (prefix)\n14. Ternary: `condition ? valueIfTrue : valueIfFalse`\n15. Parentheses for grouping: `(a + b) * c`\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\n\nBox(children: (Text | Box)[]) — A box\nText(value: string, tone?: \"a\" | \"b\")\n\n## Built-in Functions\n\nData functions prefixed with `@` to distinguish from components. These are the ONLY functions available — do NOT invent new ones.\nUse @-prefixed built-in functions (@Count, @Sum, @Avg, @Min, @Max, @Round) on Query results — do NOT hardcode computed values.\n\n@Count(array) → number — Returns array length\n@First(array) → element — Returns first element of array\n@Last(array) → element — Returns last element of array\n@Sum(numbers[]) → number — Sum of numeric array\n@Avg(numbers[]) → number — Average of numeric array\n@Min(numbers[]) → number — Minimum value in array\n@Max(numbers[]) → number — Maximum value in array\n@Sort(array, field, direction?) → sorted array — Sort array by field. Direction: \"asc\" (default) or \"desc\"\n@Filter(array, field, operator: \"==\" | \"!=\" | \">\" | \"<\" | \">=\" | \"<=\" | \"contains\", value) → filtered array — Filter array by field value\n@Round(number, decimals?) → number — Round to N decimal places (default 0)\n@Abs(number) → number — Absolute value\n@Floor(number) → number — Round down to nearest integer\n@Ceil(number) → number — Round up to nearest integer\n@Each(array, varName, template) — Evaluate template for each element. varName is the loop variable — use it ONLY inside the template expression (inline). Do NOT create a separate statement for the template.\n\nBuiltins compose — output of one is input to the next:\n`@Count(@Filter(data.rows, \"field\", \"==\", \"val\"))` for KPIs/chart values, `@Round(@Avg(data.rows.score), 1)`, `@Each(data.rows, \"item\", Comp(item.field))` for per-item rendering.\nArray pluck: `data.rows.field` extracts a field from every row → use with @Sum, @Avg, charts, tables.\n\nIMPORTANT @Each rule: The loop variable (e.g. \"item\") is ONLY available inside the @Each template expression. Always inline the template — do NOT extract it to a separate statement.\nCORRECT: `Col(\"Actions\", @Each(rows, \"t\", Button(\"Edit\", Action([@Set($id, t.id)]))))`\nWRONG: `myBtn = Button(\"Edit\", Action([@Set($id, t.id)]))` then `Col(\"Actions\", @Each(rows, \"t\", myBtn))` — t is undefined in myBtn.\n\n## Query — Live Data Fetching\n\nFetch data from available tools. Returns defaults instantly, swaps in real data when it arrives.\n\n```\nmetrics = Query(\"tool_name\", {arg1: value, arg2: $binding}, {defaultField: 0, defaultData: []}, refreshInterval?)\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (may reference $bindings — re-fetches automatically on change)\n- Third arg: default data (rendered immediately before fetch resolves)\n- Fourth arg (optional): refresh interval in seconds (e.g. 30 for auto-refresh every 30s)\n- Use dot access on results: metrics.totalEvents, metrics.data.day (array pluck)\n- Query results must use regular identifiers: `metrics = Query(...)`, NOT `$metrics = Query(...)`\n- Manual refresh: `Button(\"Refresh\", Action([@Run(query1), @Run(query2)]), \"secondary\")` — re-fetches the listed queries\n- Refresh all queries: create Action with @Run for each query\n\n## Mutation — Write Operations\n\nExecute state-changing tool calls (create, update, delete). Unlike Query (auto-fetches on render), Mutation fires only on button click via Action.\n\n```\nresult = Mutation(\"tool_name\", {arg1: $binding, arg2: \"value\"})\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (evaluated with current $binding values at click time)\n- result.status: \"idle\" | \"loading\" | \"success\" | \"error\"\n- result.data: tool response on success\n- result.error: error message on failure\n- Mutation results use regular identifiers: `result = Mutation(...)`, NOT `$result`\n- Show loading state: `result.status == \"loading\" ? TextContent(\"Saving...\") : null`\n\n## Data Workflow\n\nWhen tools are available, follow this workflow:\n1. FIRST: Call the most relevant tool to inspect the real data shape before generating code\n2. Use Query() for READ operations (data that should stay live) — NEVER hardcode tool results as literal arrays or objects\n3. Use Mutation() for WRITE operations (create, update, delete) — triggered by button clicks via Action([@Run(mutationRef)])\n4. Use the real data from step 1 as condensed Query defaults (3-5 rows) so the UI renders immediately\n5. Use @-prefixed builtins (@Count, @Filter, @Sort, @Sum) on Query results for KPIs and aggregations — the runtime evaluates these live on every refresh\n6. Hardcoded arrays are ONLY for static display data (labels, options) where no tool exists\n\nWRONG — you called a tool and got data back, but you inlined the results:\n```\nopenCount = 2\nitem1 = SomeComp(\"first item title\")\nitem2 = SomeComp(\"second item title\")\nlist = SomeList([item1, item2])\nchart = SomeChart([\"A\", \"B\"], [12, 8])\n```\nThis is static — it shows stale data and won't update. Creating item1, item2, item3... manually is ALWAYS wrong when a tool exists.\n\nRIGHT — use Query() for live data, Mutation() for writes, @builtins to derive values:\n```\ndata = Query(\"tool_name\", {}, {rows: []})\nopenCount = @Count(@Filter(data.rows, \"field\", \"==\", \"value\"))\nlist = @Each(data.rows, \"item\", SomeComp(item.title, item.field))\ncreateResult = Mutation(\"create_tool\", {title: $title})\nsubmitBtn = Button(\"Create\", Action([@Run(createResult), @Run(data), @Reset($title)]))\n```\nEverything derives from the Query — when data refreshes, the entire dashboard updates automatically.\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Root(...)` — UI shell appears immediately\n2. $variable declarations — state ready for bindings\n3. Query statements — defaults resolve immediately so components render with data\n4. Component definitions — fill in with data already available\n5. Data values — leaf content last\n\nAlways write the root = Root(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Root(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n3. Every Query result is referenced by at least one component." - } +{"name":"chat-default","spec":{"root":"Card","components":{"Card":{"signature":"Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])","description":"Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent."},"CardHeader":{"signature":"CardHeader(title?: string, subtitle?: string)","description":"Header with optional title and subtitle"},"TextContent":{"signature":"TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")","description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"MarkDownRenderer":{"signature":"MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")","description":"Renders markdown text with optional container variant"},"Callout":{"signature":"Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)","description":"Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false."},"TextCallout":{"signature":"TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)","description":"Text callout with variant, title, and description"},"Image":{"signature":"Image(alt: string, src?: string)","description":"Image with alt text and optional URL"},"ImageBlock":{"signature":"ImageBlock(src: string, alt?: string)","description":"Image block with loading state"},"ImageGallery":{"signature":"ImageGallery(images: {src: string, alt?: string, details?: string}[])","description":"Gallery grid of images with modal preview"},"CodeBlock":{"signature":"CodeBlock(language: string, codeString: string)","description":"Syntax-highlighted code block"},"Separator":{"signature":"Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)","description":"Visual divider between content sections"},"Table":{"signature":"Table(columns: Col[])","description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"signature":"Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")","description":"Column definition — holds label + data array"},"BarChart":{"signature":"BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)","description":"Vertical bars; use for comparing values across categories with one or more series"},"LineChart":{"signature":"LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)","description":"Lines over categories; use for trends and continuous data over time"},"AreaChart":{"signature":"AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)","description":"Filled area under lines; use for cumulative totals or volume trends over time"},"RadarChart":{"signature":"RadarChart(labels: string[], series: Series[])","description":"Spider/web chart; use for comparing multiple variables across one or more entities"},"HorizontalBarChart":{"signature":"HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)","description":"Horizontal bars; prefer when category labels are long or for ranked lists"},"Series":{"signature":"Series(category: string, values: number[])","description":"One data series"},"PieChart":{"signature":"PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")","description":"Circular slices; use plucked arrays: PieChart(data.categories, data.values)"},"RadialChart":{"signature":"RadialChart(labels: string[], values: number[])","description":"Radial bars; use plucked arrays: RadialChart(data.categories, data.values)"},"SingleStackedBarChart":{"signature":"SingleStackedBarChart(labels: string[], values: number[])","description":"Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)"},"Slice":{"signature":"Slice(category: string, value: number)","description":"One slice with label and numeric value"},"ScatterChart":{"signature":"ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)","description":"X/Y scatter plot; use for correlations, distributions, and clustering"},"ScatterSeries":{"signature":"ScatterSeries(name: string, points: Point[])","description":"Named dataset"},"Point":{"signature":"Point(x: number, y: number, z?: number)","description":"Data point with numeric coordinates"},"Form":{"signature":"Form(name: string, buttons: Buttons, fields?: FormControl[])","description":"Form container with fields and explicit action buttons"},"FormControl":{"signature":"FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)","description":"Field with label, input component, and optional hint text"},"Label":{"signature":"Label(text: string)","description":"Text label"},"Input":{"signature":"Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"TextArea":{"signature":"TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Select":{"signature":"Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")","description":""},"SelectItem":{"signature":"SelectItem(value: string, label: string)","description":"Option for Select"},"DatePicker":{"signature":"DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Slider":{"signature":"Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":"Numeric slider input; supports continuous and discrete (stepped) variants"},"CheckBoxGroup":{"signature":"CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)","description":""},"CheckBoxItem":{"signature":"CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)","description":""},"RadioGroup":{"signature":"RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"RadioItem":{"signature":"RadioItem(label: string, description: string, value: string)","description":""},"SwitchGroup":{"signature":"SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)","description":"Group of switch toggles"},"SwitchItem":{"signature":"SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)","description":"Individual switch toggle"},"Button":{"signature":"Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")","description":"Clickable button"},"Buttons":{"signature":"Buttons(buttons: Button[], direction?: \"row\" | \"column\")","description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"ListBlock":{"signature":"ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")","description":"A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list."},"ListItem":{"signature":"ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)","description":"Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable."},"FollowUpBlock":{"signature":"FollowUpBlock(items: FollowUpItem[])","description":"List of clickable follow-up suggestions placed at the end of a response"},"FollowUpItem":{"signature":"FollowUpItem(text: string)","description":"Clickable follow-up suggestion — when clicked, sends text as user message"},"SectionBlock":{"signature":"SectionBlock(sections: SectionItem[], isFoldable?: boolean)","description":"Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section."},"SectionItem":{"signature":"SectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[])","description":"Section with a label and collapsible content — used inside SectionBlock"},"Tabs":{"signature":"Tabs(items: TabItem[])","description":"Tabbed container"},"TabItem":{"signature":"TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[])","description":"value is unique id, trigger is tab label, content is array of components"},"Accordion":{"signature":"Accordion(items: AccordionItem[])","description":"Collapsible sections"},"AccordionItem":{"signature":"AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[])","description":"value is unique id, trigger is section title"},"Steps":{"signature":"Steps(items: StepsItem[])","description":"Step-by-step guide"},"StepsItem":{"signature":"StepsItem(title: string, details: string)","description":"title and details text for one step"},"Carousel":{"signature":"Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\")","description":"Horizontal scrollable carousel"},"TagBlock":{"signature":"TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")","description":"tags is an array of strings; optional size sm | md | lg"},"Tag":{"signature":"Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")","description":"Styled tag/badge with optional Icon and variant"},"EntityList":{"signature":"EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})","description":"Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers."},"InlineHeader":{"signature":"InlineHeader(heading: string, description?: string)","description":"Compact section heading with an optional one-line description, for use inside cards."},"Icon":{"signature":"Icon(name: string, category?: string)","description":"A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve."},"IconButton":{"signature":"IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")","description":"Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click."},"EditableTable":{"signature":"EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])","description":"Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field"},"ChipItem":{"signature":"ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)","description":"A single selectable chip inside a Chips group, with a value, label and optional icon."},"Chips":{"signature":"Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])","description":"A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`."},"OptionCard":{"signature":"OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)","description":"A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top."},"OptionCards":{"signature":"OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])","description":"A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`."},"Text":{"signature":"Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")","description":"Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"BoldText":{"signature":"BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")","description":"Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"IconText":{"signature":"IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")","description":"An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color."},"ImageText":{"signature":"ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)","description":"A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL."},"ImageTextLarge":{"signature":"ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)","description":"A full-width banner image above a bold title and optional subtitle. src must be a real image URL."},"MetricIndicatorInline":{"signature":"MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})","description":"Headline metric value with an optional +/- percentage trend and subtext, all on one line."},"MetricIndicatorWithStrikethrough":{"signature":"MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})","description":"Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below."},"SnippetCardItem":{"signature":"SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)","description":"One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)."},"SnippetCardBlock":{"signature":"SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action."},"OverviewCardItem":{"signature":"OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)","description":"One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom."},"OverviewCardBlock":{"signature":"OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action."},"ContextCardItem":{"signature":"ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)","description":"A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image."},"ContextCardBlock":{"signature":"ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable."},"CompositeCardItem":{"signature":"CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})","description":"A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer."},"CompositeCardBlock":{"signature":"CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable."},"VisualCardItem":{"signature":"VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)","description":"A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)."},"VisualCardBlock":{"signature":"VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable."}},"componentGroups":[{"name":"Content","components":["CardHeader","TextContent","MarkDownRenderer","Callout","TextCallout","Image","ImageBlock","ImageGallery","CodeBlock","Separator","InlineHeader"],"notes":["- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).","- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card."]},{"name":"Tables","components":["Table","Col","EditableTable"],"notes":["- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).","- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes."]},{"name":"Charts (2D)","components":["BarChart","LineChart","AreaChart","RadarChart","HorizontalBarChart","Series"]},{"name":"Charts (1D)","components":["PieChart","RadialChart","SingleStackedBarChart","Slice"]},{"name":"Charts (Scatter)","components":["ScatterChart","ScatterSeries","Point"]},{"name":"Forms","components":["Form","FormControl","Label","Input","TextArea","Select","SelectItem","DatePicker","Slider","CheckBoxGroup","CheckBoxItem","RadioGroup","RadioItem","SwitchGroup","SwitchItem","Chips","ChipItem","OptionCards","OptionCard"],"notes":["- Chips: compact single/multiple selection pills. Use ChipItem references for each option.","- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.","- Define EACH FormControl as its own reference — do NOT inline all controls in one array.","- NEVER nest Form inside Form.","- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).","- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }","- The renderer shows error messages automatically — do NOT generate error text in the UI"]},{"name":"Buttons","components":["Button","Buttons","Icon","IconButton"],"notes":["- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard."]},{"name":"Lists & Follow-ups","components":["ListBlock","ListItem","FollowUpBlock","FollowUpItem"],"notes":["- Use ListBlock with ListItem references for numbered lists.","- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.","- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.","- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.","- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })"]},{"name":"Sections","components":["SectionBlock","SectionItem"],"notes":["- SectionBlock renders collapsible accordion sections that auto-open as they stream.","- Each section needs a unique `value` id, a `trigger` label, and a `content` array.","- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])","- Set isFoldable=false to render sections as flat headers instead of accordion."]},{"name":"Layout","components":["Tabs","TabItem","Accordion","AccordionItem","Steps","StepsItem","Carousel"],"notes":["- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.","- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])","- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.","- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.","- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs."]},{"name":"Data Display","components":["TagBlock","Tag","EntityList"],"notes":["- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not."]},{"name":"Cards","components":["SnippetCardBlock","SnippetCardItem","OverviewCardBlock","OverviewCardItem","ContextCardBlock","ContextCardItem","CompositeCardBlock","CompositeCardItem","VisualCardBlock","VisualCardItem","Text","BoldText","IconText","ImageText","ImageTextLarge","MetricIndicatorInline","MetricIndicatorWithStrikethrough"],"notes":["- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.","- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.","- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.","- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.","- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.","- VisualCardItem: image-first card with a BoldText body and optional Tag.","- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card."]}]},"expected":"You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Content\nCardHeader(title?: string, subtitle?: string) — Header with optional title and subtitle\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nMarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\") — Renders markdown text with optional container variant\nCallout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding) — Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.\nTextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string) — Text callout with variant, title, and description\nImage(alt: string, src?: string) — Image with alt text and optional URL\nImageBlock(src: string, alt?: string) — Image block with loading state\nImageGallery(images: {src: string, alt?: string, details?: string}[]) — Gallery grid of images with modal preview\nCodeBlock(language: string, codeString: string) — Syntax-highlighted code block\nSeparator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean) — Visual divider between content sections\nInlineHeader(heading: string, description?: string) — Compact section heading with an optional one-line description, for use inside cards.\n- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).\n- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card.\n\n### Tables\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\nEditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[]) — Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field\n- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).\n- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.\n\n### Charts (2D)\nBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number) — Vertical bars; use for comparing values across categories with one or more series\nLineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Lines over categories; use for trends and continuous data over time\nAreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Filled area under lines; use for cumulative totals or volume trends over time\nRadarChart(labels: string[], series: Series[]) — Spider/web chart; use for comparing multiple variables across one or more entities\nHorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string) — Horizontal bars; prefer when category labels are long or for ranked lists\nSeries(category: string, values: number[]) — One data series\n\n### Charts (1D)\nPieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\") — Circular slices; use plucked arrays: PieChart(data.categories, data.values)\nRadialChart(labels: string[], values: number[]) — Radial bars; use plucked arrays: RadialChart(data.categories, data.values)\nSingleStackedBarChart(labels: string[], values: number[]) — Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)\nSlice(category: string, value: number) — One slice with label and numeric value\n\n### Charts (Scatter)\nScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string) — X/Y scatter plot; use for correlations, distributions, and clustering\nScatterSeries(name: string, points: Point[]) — Named dataset\nPoint(x: number, y: number, z?: number) — Data point with numeric coordinates\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nLabel(text: string) — Text label\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nTextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nDatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSlider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding) — Numeric slider input; supports continuous and discrete (stepped) variants\nCheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)\nCheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)\nRadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nRadioItem(label: string, description: string, value: string)\nSwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>) — Group of switch toggles\nSwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean) — Individual switch toggle\nChips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.\nChipItem(value: string, label: string, icon?: Icon, disabled?: boolean) — A single selectable chip inside a Chips group, with a value, label and optional icon.\nOptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.\nOptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean) — A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.\n- Chips: compact single/multiple selection pills. Use ChipItem references for each option.\n- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.\n- Define EACH FormControl as its own reference — do NOT inline all controls in one array.\n- NEVER nest Form inside Form.\n- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).\n- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }\n- The renderer shows error messages automatically — do NOT generate error text in the UI\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nIcon(name: string, category?: string) — A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.\nIconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\") — Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.\n- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.\n\n### Lists & Follow-ups\nListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\") — A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.\nListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression) — Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.\nFollowUpBlock(items: FollowUpItem[]) — List of clickable follow-up suggestions placed at the end of a response\nFollowUpItem(text: string) — Clickable follow-up suggestion — when clicked, sends text as user message\n- Use ListBlock with ListItem references for numbered lists.\n- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.\n- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.\n- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.\n- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })\n\n### Sections\nSectionBlock(sections: SectionItem[], isFoldable?: boolean) — Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section.\nSectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[]) — Section with a label and collapsible content — used inside SectionBlock\n- SectionBlock renders collapsible accordion sections that auto-open as they stream.\n- Each section needs a unique `value` id, a `trigger` label, and a `content` array.\n- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])\n- Set isFoldable=false to render sections as flat headers instead of accordion.\n\n### Layout\nTabs(items: TabItem[]) — Tabbed container\nTabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[]) — value is unique id, trigger is tab label, content is array of components\nAccordion(items: AccordionItem[]) — Collapsible sections\nAccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[]) — value is unique id, trigger is section title\nSteps(items: StepsItem[]) — Step-by-step guide\nStepsItem(title: string, details: string) — title and details text for one step\nCarousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\") — Horizontal scrollable carousel\n- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.\n- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])\n- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.\n- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.\n- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs.\n\n### Data Display\nTagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\") — tags is an array of strings; optional size sm | md | lg\nTag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\") — Styled tag/badge with optional Icon and variant\nEntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}) — Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.\n- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.\n\n### Cards\nSnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.\nSnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText) — One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).\nOverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.\nOverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline) — One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.\nContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.\nContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string) — A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.\nCompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.\nCompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button}) — A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.\nVisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.\nVisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string) — A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).\nText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nBoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nIconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\") — An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.\nImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number) — A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.\nImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean) — A full-width banner image above a bold title and optional subtitle. src must be a real image URL.\nMetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional +/- percentage trend and subtext, all on one line.\nMetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.\n- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.\n- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.\n- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.\n- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.\n- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.\n- VisualCardItem: image-first card with a BoldText body and optional Tag.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root."}, +{"name":"chat-options","spec":{"root":"Card","components":{"Card":{"signature":"Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])","description":"Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent."},"CardHeader":{"signature":"CardHeader(title?: string, subtitle?: string)","description":"Header with optional title and subtitle"},"TextContent":{"signature":"TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")","description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"MarkDownRenderer":{"signature":"MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")","description":"Renders markdown text with optional container variant"},"Callout":{"signature":"Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)","description":"Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false."},"TextCallout":{"signature":"TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)","description":"Text callout with variant, title, and description"},"Image":{"signature":"Image(alt: string, src?: string)","description":"Image with alt text and optional URL"},"ImageBlock":{"signature":"ImageBlock(src: string, alt?: string)","description":"Image block with loading state"},"ImageGallery":{"signature":"ImageGallery(images: {src: string, alt?: string, details?: string}[])","description":"Gallery grid of images with modal preview"},"CodeBlock":{"signature":"CodeBlock(language: string, codeString: string)","description":"Syntax-highlighted code block"},"Separator":{"signature":"Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)","description":"Visual divider between content sections"},"Table":{"signature":"Table(columns: Col[])","description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"signature":"Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")","description":"Column definition — holds label + data array"},"BarChart":{"signature":"BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)","description":"Vertical bars; use for comparing values across categories with one or more series"},"LineChart":{"signature":"LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)","description":"Lines over categories; use for trends and continuous data over time"},"AreaChart":{"signature":"AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)","description":"Filled area under lines; use for cumulative totals or volume trends over time"},"RadarChart":{"signature":"RadarChart(labels: string[], series: Series[])","description":"Spider/web chart; use for comparing multiple variables across one or more entities"},"HorizontalBarChart":{"signature":"HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)","description":"Horizontal bars; prefer when category labels are long or for ranked lists"},"Series":{"signature":"Series(category: string, values: number[])","description":"One data series"},"PieChart":{"signature":"PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")","description":"Circular slices; use plucked arrays: PieChart(data.categories, data.values)"},"RadialChart":{"signature":"RadialChart(labels: string[], values: number[])","description":"Radial bars; use plucked arrays: RadialChart(data.categories, data.values)"},"SingleStackedBarChart":{"signature":"SingleStackedBarChart(labels: string[], values: number[])","description":"Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)"},"Slice":{"signature":"Slice(category: string, value: number)","description":"One slice with label and numeric value"},"ScatterChart":{"signature":"ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)","description":"X/Y scatter plot; use for correlations, distributions, and clustering"},"ScatterSeries":{"signature":"ScatterSeries(name: string, points: Point[])","description":"Named dataset"},"Point":{"signature":"Point(x: number, y: number, z?: number)","description":"Data point with numeric coordinates"},"Form":{"signature":"Form(name: string, buttons: Buttons, fields?: FormControl[])","description":"Form container with fields and explicit action buttons"},"FormControl":{"signature":"FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)","description":"Field with label, input component, and optional hint text"},"Label":{"signature":"Label(text: string)","description":"Text label"},"Input":{"signature":"Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"TextArea":{"signature":"TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Select":{"signature":"Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")","description":""},"SelectItem":{"signature":"SelectItem(value: string, label: string)","description":"Option for Select"},"DatePicker":{"signature":"DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Slider":{"signature":"Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":"Numeric slider input; supports continuous and discrete (stepped) variants"},"CheckBoxGroup":{"signature":"CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)","description":""},"CheckBoxItem":{"signature":"CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)","description":""},"RadioGroup":{"signature":"RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"RadioItem":{"signature":"RadioItem(label: string, description: string, value: string)","description":""},"SwitchGroup":{"signature":"SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)","description":"Group of switch toggles"},"SwitchItem":{"signature":"SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)","description":"Individual switch toggle"},"Button":{"signature":"Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")","description":"Clickable button"},"Buttons":{"signature":"Buttons(buttons: Button[], direction?: \"row\" | \"column\")","description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"ListBlock":{"signature":"ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")","description":"A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list."},"ListItem":{"signature":"ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)","description":"Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable."},"FollowUpBlock":{"signature":"FollowUpBlock(items: FollowUpItem[])","description":"List of clickable follow-up suggestions placed at the end of a response"},"FollowUpItem":{"signature":"FollowUpItem(text: string)","description":"Clickable follow-up suggestion — when clicked, sends text as user message"},"SectionBlock":{"signature":"SectionBlock(sections: SectionItem[], isFoldable?: boolean)","description":"Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section."},"SectionItem":{"signature":"SectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[])","description":"Section with a label and collapsible content — used inside SectionBlock"},"Tabs":{"signature":"Tabs(items: TabItem[])","description":"Tabbed container"},"TabItem":{"signature":"TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[])","description":"value is unique id, trigger is tab label, content is array of components"},"Accordion":{"signature":"Accordion(items: AccordionItem[])","description":"Collapsible sections"},"AccordionItem":{"signature":"AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[])","description":"value is unique id, trigger is section title"},"Steps":{"signature":"Steps(items: StepsItem[])","description":"Step-by-step guide"},"StepsItem":{"signature":"StepsItem(title: string, details: string)","description":"title and details text for one step"},"Carousel":{"signature":"Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\")","description":"Horizontal scrollable carousel"},"TagBlock":{"signature":"TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")","description":"tags is an array of strings; optional size sm | md | lg"},"Tag":{"signature":"Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")","description":"Styled tag/badge with optional Icon and variant"},"EntityList":{"signature":"EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})","description":"Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers."},"InlineHeader":{"signature":"InlineHeader(heading: string, description?: string)","description":"Compact section heading with an optional one-line description, for use inside cards."},"Icon":{"signature":"Icon(name: string, category?: string)","description":"A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve."},"IconButton":{"signature":"IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")","description":"Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click."},"EditableTable":{"signature":"EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])","description":"Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field"},"ChipItem":{"signature":"ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)","description":"A single selectable chip inside a Chips group, with a value, label and optional icon."},"Chips":{"signature":"Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])","description":"A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`."},"OptionCard":{"signature":"OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)","description":"A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top."},"OptionCards":{"signature":"OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])","description":"A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`."},"Text":{"signature":"Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")","description":"Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"BoldText":{"signature":"BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")","description":"Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"IconText":{"signature":"IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")","description":"An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color."},"ImageText":{"signature":"ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)","description":"A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL."},"ImageTextLarge":{"signature":"ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)","description":"A full-width banner image above a bold title and optional subtitle. src must be a real image URL."},"MetricIndicatorInline":{"signature":"MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})","description":"Headline metric value with an optional +/- percentage trend and subtext, all on one line."},"MetricIndicatorWithStrikethrough":{"signature":"MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})","description":"Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below."},"SnippetCardItem":{"signature":"SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)","description":"One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)."},"SnippetCardBlock":{"signature":"SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action."},"OverviewCardItem":{"signature":"OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)","description":"One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom."},"OverviewCardBlock":{"signature":"OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action."},"ContextCardItem":{"signature":"ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)","description":"A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image."},"ContextCardBlock":{"signature":"ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable."},"CompositeCardItem":{"signature":"CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})","description":"A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer."},"CompositeCardBlock":{"signature":"CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable."},"VisualCardItem":{"signature":"VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)","description":"A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)."},"VisualCardBlock":{"signature":"VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable."}},"componentGroups":[{"name":"Content","components":["CardHeader","TextContent","MarkDownRenderer","Callout","TextCallout","Image","ImageBlock","ImageGallery","CodeBlock","Separator","InlineHeader"],"notes":["- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).","- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card."]},{"name":"Tables","components":["Table","Col","EditableTable"],"notes":["- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).","- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes."]},{"name":"Charts (2D)","components":["BarChart","LineChart","AreaChart","RadarChart","HorizontalBarChart","Series"]},{"name":"Charts (1D)","components":["PieChart","RadialChart","SingleStackedBarChart","Slice"]},{"name":"Charts (Scatter)","components":["ScatterChart","ScatterSeries","Point"]},{"name":"Forms","components":["Form","FormControl","Label","Input","TextArea","Select","SelectItem","DatePicker","Slider","CheckBoxGroup","CheckBoxItem","RadioGroup","RadioItem","SwitchGroup","SwitchItem","Chips","ChipItem","OptionCards","OptionCard"],"notes":["- Chips: compact single/multiple selection pills. Use ChipItem references for each option.","- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.","- Define EACH FormControl as its own reference — do NOT inline all controls in one array.","- NEVER nest Form inside Form.","- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).","- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }","- The renderer shows error messages automatically — do NOT generate error text in the UI"]},{"name":"Buttons","components":["Button","Buttons","Icon","IconButton"],"notes":["- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard."]},{"name":"Lists & Follow-ups","components":["ListBlock","ListItem","FollowUpBlock","FollowUpItem"],"notes":["- Use ListBlock with ListItem references for numbered lists.","- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.","- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.","- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.","- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })"]},{"name":"Sections","components":["SectionBlock","SectionItem"],"notes":["- SectionBlock renders collapsible accordion sections that auto-open as they stream.","- Each section needs a unique `value` id, a `trigger` label, and a `content` array.","- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])","- Set isFoldable=false to render sections as flat headers instead of accordion."]},{"name":"Layout","components":["Tabs","TabItem","Accordion","AccordionItem","Steps","StepsItem","Carousel"],"notes":["- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.","- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])","- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.","- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.","- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs."]},{"name":"Data Display","components":["TagBlock","Tag","EntityList"],"notes":["- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not."]},{"name":"Cards","components":["SnippetCardBlock","SnippetCardItem","OverviewCardBlock","OverviewCardItem","ContextCardBlock","ContextCardItem","CompositeCardBlock","CompositeCardItem","VisualCardBlock","VisualCardItem","Text","BoldText","IconText","ImageText","ImageTextLarge","MetricIndicatorInline","MetricIndicatorWithStrikethrough"],"notes":["- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.","- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.","- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.","- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.","- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.","- VisualCardItem: image-first card with a BoldText body and optional Tag.","- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card."]}],"examples":["Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }","Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")","Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)","Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }","Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")"],"additionalRules":["When asked about data, generate realistic/plausible data","Every response is a single Card(children) — children stack vertically automatically. No layout params are needed on Card.","Card is the only layout container. Do NOT use Stack. Use Tabs to switch between sections, Carousel for horizontal scroll.","Use FollowUpBlock at the END of a Card to suggest what the user can do or ask next.","Use ListBlock when presenting a set of options or steps; give each ListItem an action (5th argument) to make it clickable — without one the item is plain text.","Use SectionBlock to group long responses into collapsible sections — good for reports, FAQs, and structured content.","Use SectionItem inside SectionBlock: each item needs a unique value id, a trigger (header label), and a content array.","Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])","IMPORTANT: Every slide in a Carousel must use the same component structure in the same order — e.g. all slides: [title, image, description, tags].","For forms, define one FormControl reference per field so controls can stream progressively.","For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).","Never nest Form inside Form.","CardHeader is the page-level heading — place it as the first child of Card; InlineHeader is a lighter subsection label for a block inside the response, and is redundant when the following component already has a heading.","Never use Callout or TextCallout to justify why you did what you did or for any meta-information.","Every image slot (Image, ImageBlock, ImageGallery, VisualCardItem/ContextCardItem bgImageSrc, ImageText, ImageTextLarge, ListItem image) requires a REAL URL from a tool result, the conversation, or the user — NEVER invent, guess, or template a URL.","If no image URL is in context, compose without image components — icons, gray ContextCardItems, and charts still make rich layouts.","Argument-order trap: Image takes alt FIRST, while ImageBlock, ImageText, and ImageTextLarge take src FIRST — alt text in a src slot ships a broken image.","Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items, all with the same structure; use layout \"grid\" for primary side-by-side comparison and \"carousel\" for secondary browsing.","The card-block action is BLOCK-LEVEL: one action shared by every card, with the clicked card's details attached automatically — keep continue_conversation context generic (e.g. \"Tell me more about this destination\"), and never use a block-level open_url since it would send every card to the same URL.","Card items have NO per-item action: to give each item its own external link, use CompositeCardItem with footer { button: Button(label, { type: \"open_url\", url }) } — never claim a card opens a link it cannot.","Text, BoldText, IconText, ImageText, ImageTextLarge and MetricIndicator* are inline building blocks used INSIDE card items — do not place them directly in the root Card.","EntityList size \"small\" is reserved for CompositeCardItem body content (no header/footer); use size \"default\" elsewhere.","Tag variant must be semantically correct (success=positive, danger=negative, warning=cautionary, info=informational, neutral=label); Tag takes an optional Icon second, so use Tag(text, icon, size, variant) when a variant is needed.","TagBlock takes plain strings — keep it to at most 3 tags.","ListBlock variant \"number\" is for ordered sequences and rankings, \"image\" for products/profiles with a real image; Steps is for ordered sequential processes only.","Use SectionBlock to divide a long response into independent, equally prominent topics; use Tabs when the items are alternative views of the same thing; set isFoldable=false unless a section has 4+ distinct blocks; never make SectionBlock the first Card child.","Accordion is for supplementary or FAQ content only — never primary information, 3-5 items max, and always the last component in its section or card.","Charts: LineChart/AreaChart variant \"natural\" for smooth trends and \"linear\" for precise point-to-point data; BarChart \"grouped\" for side-by-side comparison and \"stacked\" for part-to-whole; prefer HorizontalBarChart when category labels are long or numerous.","For large chart values, scale the data and put the unit in the axis label (e.g. yLabel \"Revenue ($k)\") instead of passing raw thousands or millions.","Quantitative asks get a chart (plus KPI cards where useful) in the FIRST response — do not answer numbers with prose or a table alone.","Table is column-oriented: each Col holds its own data array of plain strings or numbers (never components), and every column's array must have the same length.","Use EditableTable ONLY when the user or app explicitly asks for an editable table; default to Table for read-only data.","Every Form MUST have EXACTLY ONE submit Button with variant \"primary\" — that button validates the form; other buttons (secondary/tertiary escape hatches like \"Just Surprise Me\") skip validation, and there is never a reset button.","Prefer structured inputs (Select, Chips, OptionCards, DatePicker, Slider) over free-text Input, give every FormControl a clear label (and a hint where it prevents mistakes), and keep each field name unique within the response.","Validation rules ({ required: true, email: true, minLength: 8, ... }) are enforced with inline errors — use them for genuinely essential fields, but never require a free-text field where leaving it blank is meaningful.","Form inputs work ONLY inside a FormControl within a Form; for tappable suggestion choices OUTSIDE a form, use Buttons of continue_conversation Buttons — never a bare OptionCards or Chips.","Only add Buttons for real actions: form submit, open_url with a URL from a tool or the user (never fabricated), or a continue_conversation follow-up — never a button for an app action (open, download, export, edit) you cannot perform.","Every Button label must accurately describe what clicking it does; use \"primary\" for the main action and \"secondary\"/\"tertiary\" only for lower-emphasis supporting actions.","Icon: always include the category argument — it enables fallback matching when the exact lucide name is unavailable.","Pass sources on Card ONLY when the answer relies on real references you actually have, and cite them inline in TextContent as [1], [2] (1-based index into sources)."]},"expected":"You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Content\nCardHeader(title?: string, subtitle?: string) — Header with optional title and subtitle\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nMarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\") — Renders markdown text with optional container variant\nCallout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding) — Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.\nTextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string) — Text callout with variant, title, and description\nImage(alt: string, src?: string) — Image with alt text and optional URL\nImageBlock(src: string, alt?: string) — Image block with loading state\nImageGallery(images: {src: string, alt?: string, details?: string}[]) — Gallery grid of images with modal preview\nCodeBlock(language: string, codeString: string) — Syntax-highlighted code block\nSeparator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean) — Visual divider between content sections\nInlineHeader(heading: string, description?: string) — Compact section heading with an optional one-line description, for use inside cards.\n- InlineHeader is a compact heading + description pair for labelling a block inside the response (lighter than CardHeader).\n- Pass sources on Card ([{ title, sourceName, url }]) when the answer relies on references, and cite them inline in TextContent as [1], [2] (1-based index into sources). A Sources strip renders at the bottom of the card.\n\n### Tables\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\nEditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[]) — Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field\n- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).\n- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.\n\n### Charts (2D)\nBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number) — Vertical bars; use for comparing values across categories with one or more series\nLineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Lines over categories; use for trends and continuous data over time\nAreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Filled area under lines; use for cumulative totals or volume trends over time\nRadarChart(labels: string[], series: Series[]) — Spider/web chart; use for comparing multiple variables across one or more entities\nHorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string) — Horizontal bars; prefer when category labels are long or for ranked lists\nSeries(category: string, values: number[]) — One data series\n\n### Charts (1D)\nPieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\") — Circular slices; use plucked arrays: PieChart(data.categories, data.values)\nRadialChart(labels: string[], values: number[]) — Radial bars; use plucked arrays: RadialChart(data.categories, data.values)\nSingleStackedBarChart(labels: string[], values: number[]) — Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)\nSlice(category: string, value: number) — One slice with label and numeric value\n\n### Charts (Scatter)\nScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string) — X/Y scatter plot; use for correlations, distributions, and clustering\nScatterSeries(name: string, points: Point[]) — Named dataset\nPoint(x: number, y: number, z?: number) — Data point with numeric coordinates\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nLabel(text: string) — Text label\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nTextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nDatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSlider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding) — Numeric slider input; supports continuous and discrete (stepped) variants\nCheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)\nCheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)\nRadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nRadioItem(label: string, description: string, value: string)\nSwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>) — Group of switch toggles\nSwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean) — Individual switch toggle\nChips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.\nChipItem(value: string, label: string, icon?: Icon, disabled?: boolean) — A single selectable chip inside a Chips group, with a value, label and optional icon.\nOptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.\nOptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean) — A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.\n- Chips: compact single/multiple selection pills. Use ChipItem references for each option.\n- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.\n- Define EACH FormControl as its own reference — do NOT inline all controls in one array.\n- NEVER nest Form inside Form.\n- Form requires explicit buttons. Always pass a Buttons(...) reference as the second Form argument: Form(name, buttons, fields).\n- rules is an optional object: { required: true, email: true, min: 8, maxLength: 100 }\n- The renderer shows error messages automatically — do NOT generate error text in the UI\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nIcon(name: string, category?: string) — A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.\nIconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\") — Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.\n- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.\n\n### Lists & Follow-ups\nListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\") — A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.\nListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression) — Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.\nFollowUpBlock(items: FollowUpItem[]) — List of clickable follow-up suggestions placed at the end of a response\nFollowUpItem(text: string) — Clickable follow-up suggestion — when clicked, sends text as user message\n- Use ListBlock with ListItem references for numbered lists.\n- Use FollowUpBlock with FollowUpItem references at the end of a response to suggest next actions.\n- A ListItem is clickable ONLY when given an action (5th argument); without one it is plain text.\n- Clicking a FollowUpItem, or a ListItem with a continue_conversation action, sends text to the LLM as a user message.\n- Example: list = ListBlock([item1, item2]) item1 = ListItem(\"Option A\", \"Details about A\", null, null, { type: \"continue_conversation\", context: \"Option A\" })\n\n### Sections\nSectionBlock(sections: SectionItem[], isFoldable?: boolean) — Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section.\nSectionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Tabs | Accordion)[]) — Section with a label and collapsible content — used inside SectionBlock\n- SectionBlock renders collapsible accordion sections that auto-open as they stream.\n- Each section needs a unique `value` id, a `trigger` label, and a `content` array.\n- Example: sections = SectionBlock([s1, s2]) s1 = SectionItem(\"intro\", \"Introduction\", [content1])\n- Set isFoldable=false to render sections as flat headers instead of accordion.\n\n### Layout\nTabs(items: TabItem[]) — Tabbed container\nTabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | Accordion)[]) — value is unique id, trigger is tab label, content is array of components\nAccordion(items: AccordionItem[]) — Collapsible sections\nAccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[]) — value is unique id, trigger is section title\nSteps(items: StepsItem[]) — Step-by-step guide\nStepsItem(title: string, details: string) — title and details text for one step\nCarousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock)[][], variant?: \"card\" | \"sunk\") — Horizontal scrollable carousel\n- Use Tabs to present alternative views — each TabItem has a value id, trigger label, and content array.\n- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])\n- IMPORTANT: Every slide in a Carousel must have the same structure — same component types in the same order.\n- For image carousels use: [[title, image, description, tags], ...] — every slide must follow this exact pattern.\n- Use real, publicly accessible image URLs (e.g. https://picsum.photos/seed/KEYWORD/800/500). Never hallucinate image URLs.\n\n### Data Display\nTagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\") — tags is an array of strings; optional size sm | md | lg\nTag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\") — Styled tag/badge with optional Icon and variant\nEntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}) — Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.\n- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.\n\n### Cards\nSnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.\nSnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText) — One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).\nOverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.\nOverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline) — One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.\nContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.\nContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string) — A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.\nCompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.\nCompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button}) — A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.\nVisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.\nVisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string) — A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).\nText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nBoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nIconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\") — An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.\nImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number) — A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.\nImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean) — A full-width banner image above a bold title and optional subtitle. src must be a real image URL.\nMetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional +/- percentage trend and subtext, all on one line.\nMetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.\n- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.\n- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.\n- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.\n- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.\n- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.\n- VisualCardItem: image-first card with a BoldText body and optional Tag.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n\n## Examples\n\nExample 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }\n\nExample 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")\n\nExample 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)\n\nExample 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }\n\nExample 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")\n\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n\n- When asked about data, generate realistic/plausible data\n- Every response is a single Card(children) — children stack vertically automatically. No layout params are needed on Card.\n- Card is the only layout container. Do NOT use Stack. Use Tabs to switch between sections, Carousel for horizontal scroll.\n- Use FollowUpBlock at the END of a Card to suggest what the user can do or ask next.\n- Use ListBlock when presenting a set of options or steps; give each ListItem an action (5th argument) to make it clickable — without one the item is plain text.\n- Use SectionBlock to group long responses into collapsible sections — good for reports, FAQs, and structured content.\n- Use SectionItem inside SectionBlock: each item needs a unique value id, a trigger (header label), and a content array.\n- Carousel takes an array of slides, where each slide is an array of content: carousel = Carousel([[t1, img1], [t2, img2]])\n- IMPORTANT: Every slide in a Carousel must use the same component structure in the same order — e.g. all slides: [title, image, description, tags].\n- For forms, define one FormControl reference per field so controls can stream progressively.\n- For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).\n- Never nest Form inside Form.\n- CardHeader is the page-level heading — place it as the first child of Card; InlineHeader is a lighter subsection label for a block inside the response, and is redundant when the following component already has a heading.\n- Never use Callout or TextCallout to justify why you did what you did or for any meta-information.\n- Every image slot (Image, ImageBlock, ImageGallery, VisualCardItem/ContextCardItem bgImageSrc, ImageText, ImageTextLarge, ListItem image) requires a REAL URL from a tool result, the conversation, or the user — NEVER invent, guess, or template a URL.\n- If no image URL is in context, compose without image components — icons, gray ContextCardItems, and charts still make rich layouts.\n- Argument-order trap: Image takes alt FIRST, while ImageBlock, ImageText, and ImageTextLarge take src FIRST — alt text in a src slot ships a broken image.\n- Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items, all with the same structure; use layout \"grid\" for primary side-by-side comparison and \"carousel\" for secondary browsing.\n- The card-block action is BLOCK-LEVEL: one action shared by every card, with the clicked card's details attached automatically — keep continue_conversation context generic (e.g. \"Tell me more about this destination\"), and never use a block-level open_url since it would send every card to the same URL.\n- Card items have NO per-item action: to give each item its own external link, use CompositeCardItem with footer { button: Button(label, { type: \"open_url\", url }) } — never claim a card opens a link it cannot.\n- Text, BoldText, IconText, ImageText, ImageTextLarge and MetricIndicator* are inline building blocks used INSIDE card items — do not place them directly in the root Card.\n- EntityList size \"small\" is reserved for CompositeCardItem body content (no header/footer); use size \"default\" elsewhere.\n- Tag variant must be semantically correct (success=positive, danger=negative, warning=cautionary, info=informational, neutral=label); Tag takes an optional Icon second, so use Tag(text, icon, size, variant) when a variant is needed.\n- TagBlock takes plain strings — keep it to at most 3 tags.\n- ListBlock variant \"number\" is for ordered sequences and rankings, \"image\" for products/profiles with a real image; Steps is for ordered sequential processes only.\n- Use SectionBlock to divide a long response into independent, equally prominent topics; use Tabs when the items are alternative views of the same thing; set isFoldable=false unless a section has 4+ distinct blocks; never make SectionBlock the first Card child.\n- Accordion is for supplementary or FAQ content only — never primary information, 3-5 items max, and always the last component in its section or card.\n- Charts: LineChart/AreaChart variant \"natural\" for smooth trends and \"linear\" for precise point-to-point data; BarChart \"grouped\" for side-by-side comparison and \"stacked\" for part-to-whole; prefer HorizontalBarChart when category labels are long or numerous.\n- For large chart values, scale the data and put the unit in the axis label (e.g. yLabel \"Revenue ($k)\") instead of passing raw thousands or millions.\n- Quantitative asks get a chart (plus KPI cards where useful) in the FIRST response — do not answer numbers with prose or a table alone.\n- Table is column-oriented: each Col holds its own data array of plain strings or numbers (never components), and every column's array must have the same length.\n- Use EditableTable ONLY when the user or app explicitly asks for an editable table; default to Table for read-only data.\n- Every Form MUST have EXACTLY ONE submit Button with variant \"primary\" — that button validates the form; other buttons (secondary/tertiary escape hatches like \"Just Surprise Me\") skip validation, and there is never a reset button.\n- Prefer structured inputs (Select, Chips, OptionCards, DatePicker, Slider) over free-text Input, give every FormControl a clear label (and a hint where it prevents mistakes), and keep each field name unique within the response.\n- Validation rules ({ required: true, email: true, minLength: 8, ... }) are enforced with inline errors — use them for genuinely essential fields, but never require a free-text field where leaving it blank is meaningful.\n- Form inputs work ONLY inside a FormControl within a Form; for tappable suggestion choices OUTSIDE a form, use Buttons of continue_conversation Buttons — never a bare OptionCards or Chips.\n- Only add Buttons for real actions: form submit, open_url with a URL from a tool or the user (never fabricated), or a continue_conversation follow-up — never a button for an app action (open, download, export, edit) you cannot perform.\n- Every Button label must accurately describe what clicking it does; use \"primary\" for the main action and \"secondary\"/\"tertiary\" only for lower-emphasis supporting actions.\n- Icon: always include the category argument — it enables fallback matching when the exact lucide name is unavailable.\n- Pass sources on Card ONLY when the answer relies on real references you actually have, and cite them inline in TextContent as [1], [2] (1-based index into sources)."}, +{"name":"openui-default","spec":{"root":"Stack","components":{"Card":{"signature":"Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)","description":"Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts."},"CardHeader":{"signature":"CardHeader(title?: string, subtitle?: string)","description":"Header with optional title and subtitle"},"TextContent":{"signature":"TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")","description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"MarkDownRenderer":{"signature":"MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")","description":"Renders markdown text with optional container variant"},"Callout":{"signature":"Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)","description":"Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false."},"TextCallout":{"signature":"TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)","description":"Text callout with variant, title, and description"},"Image":{"signature":"Image(alt: string, src?: string)","description":"Image with alt text and optional URL"},"ImageBlock":{"signature":"ImageBlock(src: string, alt?: string)","description":"Image block with loading state"},"ImageGallery":{"signature":"ImageGallery(images: {src: string, alt?: string, details?: string}[])","description":"Gallery grid of images with modal preview"},"CodeBlock":{"signature":"CodeBlock(language: string, codeString: string)","description":"Syntax-highlighted code block"},"InlineHeader":{"signature":"InlineHeader(heading: string, description?: string)","description":"Compact section heading with an optional one-line description, for use inside cards."},"Table":{"signature":"Table(columns: Col[])","description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"signature":"Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")","description":"Column definition — holds label + data array"},"EditableTable":{"signature":"EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])","description":"Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field"},"BarChart":{"signature":"BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)","description":"Vertical bars; use for comparing values across categories with one or more series"},"LineChart":{"signature":"LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)","description":"Lines over categories; use for trends and continuous data over time"},"AreaChart":{"signature":"AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)","description":"Filled area under lines; use for cumulative totals or volume trends over time"},"RadarChart":{"signature":"RadarChart(labels: string[], series: Series[])","description":"Spider/web chart; use for comparing multiple variables across one or more entities"},"HorizontalBarChart":{"signature":"HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)","description":"Horizontal bars; prefer when category labels are long or for ranked lists"},"Series":{"signature":"Series(category: string, values: number[])","description":"One data series"},"PieChart":{"signature":"PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")","description":"Circular slices; use plucked arrays: PieChart(data.categories, data.values)"},"RadialChart":{"signature":"RadialChart(labels: string[], values: number[])","description":"Radial bars; use plucked arrays: RadialChart(data.categories, data.values)"},"SingleStackedBarChart":{"signature":"SingleStackedBarChart(labels: string[], values: number[])","description":"Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)"},"Slice":{"signature":"Slice(category: string, value: number)","description":"One slice with label and numeric value"},"ScatterChart":{"signature":"ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)","description":"X/Y scatter plot; use for correlations, distributions, and clustering"},"ScatterSeries":{"signature":"ScatterSeries(name: string, points: Point[])","description":"Named dataset"},"Point":{"signature":"Point(x: number, y: number, z?: number)","description":"Data point with numeric coordinates"},"Form":{"signature":"Form(name: string, buttons: Buttons, fields?: FormControl[])","description":"Form container with fields and explicit action buttons"},"FormControl":{"signature":"FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)","description":"Field with label, input component, and optional hint text"},"Label":{"signature":"Label(text: string)","description":"Text label"},"Input":{"signature":"Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"TextArea":{"signature":"TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Select":{"signature":"Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")","description":""},"SelectItem":{"signature":"SelectItem(value: string, label: string)","description":"Option for Select"},"DatePicker":{"signature":"DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Slider":{"signature":"Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":"Numeric slider input; supports continuous and discrete (stepped) variants"},"CheckBoxGroup":{"signature":"CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)","description":""},"CheckBoxItem":{"signature":"CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)","description":""},"RadioGroup":{"signature":"RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"RadioItem":{"signature":"RadioItem(label: string, description: string, value: string)","description":""},"SwitchGroup":{"signature":"SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)","description":"Group of switch toggles"},"SwitchItem":{"signature":"SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)","description":"Individual switch toggle"},"ChipItem":{"signature":"ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)","description":"A single selectable chip inside a Chips group, with a value, label and optional icon."},"Chips":{"signature":"Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])","description":"A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`."},"OptionCard":{"signature":"OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)","description":"A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top."},"OptionCards":{"signature":"OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])","description":"A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`."},"Button":{"signature":"Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")","description":"Clickable button"},"Buttons":{"signature":"Buttons(buttons: Button[], direction?: \"row\" | \"column\")","description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"IconButton":{"signature":"IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")","description":"Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click."},"Stack":{"signature":"Stack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)","description":"Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"."},"Tabs":{"signature":"Tabs(items: TabItem[])","description":"Tabbed container"},"TabItem":{"signature":"TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])","description":"value is unique id, trigger is tab label, content is array of components"},"Accordion":{"signature":"Accordion(items: AccordionItem[])","description":"Collapsible sections"},"AccordionItem":{"signature":"AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])","description":"value is unique id, trigger is section title"},"Steps":{"signature":"Steps(items: StepsItem[])","description":"Step-by-step guide"},"StepsItem":{"signature":"StepsItem(title: string, details: string)","description":"title and details text for one step"},"Carousel":{"signature":"Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\")","description":"Horizontal scrollable carousel"},"Separator":{"signature":"Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)","description":"Visual divider between content sections"},"TagBlock":{"signature":"TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")","description":"tags is an array of strings; optional size sm | md | lg"},"Tag":{"signature":"Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")","description":"Styled tag/badge with optional Icon and variant"},"Icon":{"signature":"Icon(name: string, category?: string)","description":"A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve."},"EntityList":{"signature":"EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})","description":"Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers."},"ListBlock":{"signature":"ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")","description":"A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list."},"ListItem":{"signature":"ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)","description":"Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable."},"Text":{"signature":"Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")","description":"Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"BoldText":{"signature":"BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")","description":"Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"IconText":{"signature":"IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")","description":"An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color."},"ImageText":{"signature":"ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)","description":"A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL."},"ImageTextLarge":{"signature":"ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)","description":"A full-width banner image above a bold title and optional subtitle. src must be a real image URL."},"MetricIndicatorInline":{"signature":"MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})","description":"Headline metric value with an optional +/- percentage trend and subtext, all on one line."},"MetricIndicatorWithStrikethrough":{"signature":"MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})","description":"Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below."},"SnippetCardItem":{"signature":"SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)","description":"One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)."},"SnippetCardBlock":{"signature":"SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action."},"OverviewCardItem":{"signature":"OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)","description":"One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom."},"OverviewCardBlock":{"signature":"OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action."},"ContextCardItem":{"signature":"ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)","description":"A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image."},"ContextCardBlock":{"signature":"ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable."},"CompositeCardItem":{"signature":"CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})","description":"A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer."},"CompositeCardBlock":{"signature":"CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable."},"VisualCardItem":{"signature":"VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)","description":"A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)."},"VisualCardBlock":{"signature":"VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable."},"Modal":{"signature":"Modal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\")","description":"Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children."}},"componentGroups":[{"name":"Layout","components":["Stack","Tabs","TabItem","Accordion","AccordionItem","Steps","StepsItem","Carousel","Separator","Modal"],"notes":["- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.","- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.","- Use nested Stacks when you need explicit rows/sections.","- Show/hide sections: $editId != \"\" ? Card([editForm]) : null","- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.","- Use Tabs for alternative views (chart types, data sections) — no $variable needed","- Shared filter across Tabs: same $days binding in Query args works across all TabItems"]},{"name":"Content","components":["Card","CardHeader","TextContent","MarkDownRenderer","Callout","TextCallout","Image","ImageBlock","ImageGallery","CodeBlock","InlineHeader"],"notes":["- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).","- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.","- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null","- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])"]},{"name":"Tables","components":["Table","Col","EditableTable"],"notes":["- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).","- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.","- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName","- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))","- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))","- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data","- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input","- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts","- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")"]},{"name":"Charts (2D)","components":["BarChart","LineChart","AreaChart","RadarChart","HorizontalBarChart","Series"],"notes":["- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])","- Use Cards to wrap charts with CardHeader for titled sections","- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data","- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])"]},{"name":"Charts (1D)","components":["PieChart","RadialChart","SingleStackedBarChart","Slice"],"notes":["- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:","- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`","- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`"]},{"name":"Charts (Scatter)","components":["ScatterChart","ScatterSeries","Point"]},{"name":"Forms","components":["Form","FormControl","Label","Input","TextArea","Select","SelectItem","DatePicker","Slider","CheckBoxGroup","CheckBoxItem","RadioGroup","RadioItem","SwitchGroup","SwitchItem","Chips","ChipItem","OptionCards","OptionCard"],"notes":["- Chips: compact single/multiple selection pills. Use ChipItem references for each option.","- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.","- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.","- NEVER nest Form inside Form — each Form should be a standalone container.","- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.","- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}","- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric","- The renderer shows error messages automatically — do NOT generate error text in the UI","- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField","- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal."]},{"name":"Buttons","components":["Button","Buttons","IconButton"],"notes":["- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.","- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))"]},{"name":"Data Display","components":["TagBlock","Tag","Icon","EntityList","ListBlock","ListItem"],"notes":["- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")","- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.","- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional."]},{"name":"Cards","components":["SnippetCardBlock","SnippetCardItem","OverviewCardBlock","OverviewCardItem","ContextCardBlock","ContextCardItem","CompositeCardBlock","CompositeCardItem","VisualCardBlock","VisualCardItem","Text","BoldText","IconText","ImageText","ImageTextLarge","MetricIndicatorInline","MetricIndicatorWithStrikethrough"],"notes":["- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.","- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.","- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.","- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.","- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.","- VisualCardItem: image-first card with a BoldText body and optional Tag.","- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card."]}],"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"Card":{"$ref":"#/$defs/Card"},"CardHeader":{"$ref":"#/$defs/CardHeader"},"TextContent":{"$ref":"#/$defs/TextContent"},"MarkDownRenderer":{"$ref":"#/$defs/MarkDownRenderer"},"Callout":{"$ref":"#/$defs/Callout"},"TextCallout":{"$ref":"#/$defs/TextCallout"},"Image":{"$ref":"#/$defs/Image"},"ImageBlock":{"$ref":"#/$defs/ImageBlock"},"ImageGallery":{"$ref":"#/$defs/ImageGallery"},"CodeBlock":{"$ref":"#/$defs/CodeBlock"},"InlineHeader":{"$ref":"#/$defs/InlineHeader"},"Table":{"$ref":"#/$defs/Table"},"Col":{"$ref":"#/$defs/Col"},"EditableTable":{"$ref":"#/$defs/EditableTable"},"BarChart":{"$ref":"#/$defs/BarChart"},"LineChart":{"$ref":"#/$defs/LineChart"},"AreaChart":{"$ref":"#/$defs/AreaChart"},"RadarChart":{"$ref":"#/$defs/RadarChart"},"HorizontalBarChart":{"$ref":"#/$defs/HorizontalBarChart"},"Series":{"$ref":"#/$defs/Series"},"PieChart":{"$ref":"#/$defs/PieChart"},"RadialChart":{"$ref":"#/$defs/RadialChart"},"SingleStackedBarChart":{"$ref":"#/$defs/SingleStackedBarChart"},"Slice":{"$ref":"#/$defs/Slice"},"ScatterChart":{"$ref":"#/$defs/ScatterChart"},"ScatterSeries":{"$ref":"#/$defs/ScatterSeries"},"Point":{"$ref":"#/$defs/Point"},"Form":{"$ref":"#/$defs/Form"},"FormControl":{"$ref":"#/$defs/FormControl"},"Label":{"$ref":"#/$defs/Label"},"Input":{"$ref":"#/$defs/Input"},"TextArea":{"$ref":"#/$defs/TextArea"},"Select":{"$ref":"#/$defs/Select"},"SelectItem":{"$ref":"#/$defs/SelectItem"},"DatePicker":{"$ref":"#/$defs/DatePicker"},"Slider":{"$ref":"#/$defs/Slider"},"CheckBoxGroup":{"$ref":"#/$defs/CheckBoxGroup"},"CheckBoxItem":{"$ref":"#/$defs/CheckBoxItem"},"RadioGroup":{"$ref":"#/$defs/RadioGroup"},"RadioItem":{"$ref":"#/$defs/RadioItem"},"SwitchGroup":{"$ref":"#/$defs/SwitchGroup"},"SwitchItem":{"$ref":"#/$defs/SwitchItem"},"ChipItem":{"$ref":"#/$defs/ChipItem"},"Chips":{"$ref":"#/$defs/Chips"},"OptionCard":{"$ref":"#/$defs/OptionCard"},"OptionCards":{"$ref":"#/$defs/OptionCards"},"Button":{"$ref":"#/$defs/Button"},"Buttons":{"$ref":"#/$defs/Buttons"},"IconButton":{"$ref":"#/$defs/IconButton"},"Stack":{"$ref":"#/$defs/Stack"},"Tabs":{"$ref":"#/$defs/Tabs"},"TabItem":{"$ref":"#/$defs/TabItem"},"Accordion":{"$ref":"#/$defs/Accordion"},"AccordionItem":{"$ref":"#/$defs/AccordionItem"},"Steps":{"$ref":"#/$defs/Steps"},"StepsItem":{"$ref":"#/$defs/StepsItem"},"Carousel":{"$ref":"#/$defs/Carousel"},"Separator":{"$ref":"#/$defs/Separator"},"TagBlock":{"$ref":"#/$defs/TagBlock"},"Tag":{"$ref":"#/$defs/Tag"},"Icon":{"$ref":"#/$defs/Icon"},"EntityList":{"$ref":"#/$defs/EntityList"},"ListBlock":{"$ref":"#/$defs/ListBlock"},"ListItem":{"$ref":"#/$defs/ListItem"},"Text":{"$ref":"#/$defs/Text"},"BoldText":{"$ref":"#/$defs/BoldText"},"IconText":{"$ref":"#/$defs/IconText"},"ImageText":{"$ref":"#/$defs/ImageText"},"ImageTextLarge":{"$ref":"#/$defs/ImageTextLarge"},"MetricIndicatorInline":{"$ref":"#/$defs/MetricIndicatorInline"},"MetricIndicatorWithStrikethrough":{"$ref":"#/$defs/MetricIndicatorWithStrikethrough"},"SnippetCardItem":{"$ref":"#/$defs/SnippetCardItem"},"SnippetCardBlock":{"$ref":"#/$defs/SnippetCardBlock"},"OverviewCardItem":{"$ref":"#/$defs/OverviewCardItem"},"OverviewCardBlock":{"$ref":"#/$defs/OverviewCardBlock"},"ContextCardItem":{"$ref":"#/$defs/ContextCardItem"},"ContextCardBlock":{"$ref":"#/$defs/ContextCardBlock"},"CompositeCardItem":{"$ref":"#/$defs/CompositeCardItem"},"CompositeCardBlock":{"$ref":"#/$defs/CompositeCardBlock"},"VisualCardItem":{"$ref":"#/$defs/VisualCardItem"},"VisualCardBlock":{"$ref":"#/$defs/VisualCardBlock"},"Modal":{"$ref":"#/$defs/Modal"}},"required":["Card","CardHeader","TextContent","MarkDownRenderer","Callout","TextCallout","Image","ImageBlock","ImageGallery","CodeBlock","InlineHeader","Table","Col","EditableTable","BarChart","LineChart","AreaChart","RadarChart","HorizontalBarChart","Series","PieChart","RadialChart","SingleStackedBarChart","Slice","ScatterChart","ScatterSeries","Point","Form","FormControl","Label","Input","TextArea","Select","SelectItem","DatePicker","Slider","CheckBoxGroup","CheckBoxItem","RadioGroup","RadioItem","SwitchGroup","SwitchItem","ChipItem","Chips","OptionCard","OptionCards","Button","Buttons","IconButton","Stack","Tabs","TabItem","Accordion","AccordionItem","Steps","StepsItem","Carousel","Separator","TagBlock","Tag","Icon","EntityList","ListBlock","ListItem","Text","BoldText","IconText","ImageText","ImageTextLarge","MetricIndicatorInline","MetricIndicatorWithStrikethrough","SnippetCardItem","SnippetCardBlock","OverviewCardItem","OverviewCardBlock","ContextCardItem","ContextCardBlock","CompositeCardItem","CompositeCardBlock","VisualCardItem","VisualCardBlock","Modal"],"additionalProperties":false,"$defs":{"Card":{"type":"object","properties":{"children":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"},{"$ref":"#/$defs/Tabs"},{"$ref":"#/$defs/Carousel"},{"$ref":"#/$defs/Stack"}]}},"variant":{"type":"string","enum":["card","sunk","clear"]},"direction":{"type":"string","enum":["row","column"]},"gap":{"type":"string","enum":["none","xs","s","m","l","xl","2xl"]},"align":{"type":"string","enum":["start","center","end","stretch","baseline"]},"justify":{"type":"string","enum":["start","center","end","between","around","evenly"]},"wrap":{"type":"boolean"}},"required":["children"],"additionalProperties":false,"description":"Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts."},"TextContent":{"type":"object","properties":{"text":{"type":"string"},"size":{"type":"string","enum":["small","default","large","small-heavy","large-heavy"]}},"required":["text"],"additionalProperties":false,"description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"MarkDownRenderer":{"type":"object","properties":{"textMarkdown":{"type":"string"},"variant":{"type":"string","enum":["clear","card","sunk"]}},"required":["textMarkdown"],"additionalProperties":false,"description":"Renders markdown text with optional container variant"},"CardHeader":{"type":"object","properties":{"title":{"type":"string"},"subtitle":{"type":"string"}},"additionalProperties":false,"description":"Header with optional title and subtitle"},"Callout":{"type":"object","properties":{"variant":{"type":"string","enum":["info","warning","error","success","neutral"]},"title":{"type":"string"},"description":{"type":"string"},"visible":{"type":"boolean"}},"required":["variant","title","description"],"additionalProperties":false,"description":"Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false."},"TextCallout":{"type":"object","properties":{"variant":{"type":"string","enum":["neutral","info","warning","success","danger"]},"title":{"type":"string"},"description":{"type":"string"}},"additionalProperties":false,"description":"Text callout with variant, title, and description"},"CodeBlock":{"type":"object","properties":{"language":{"type":"string"},"codeString":{"type":"string"}},"required":["language","codeString"],"additionalProperties":false,"description":"Syntax-highlighted code block"},"Image":{"type":"object","properties":{"alt":{"type":"string"},"src":{"type":"string"}},"required":["alt"],"additionalProperties":false,"description":"Image with alt text and optional URL"},"ImageBlock":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"}},"required":["src"],"additionalProperties":false,"description":"Image block with loading state"},"ImageGallery":{"type":"object","properties":{"images":{"type":"array","items":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"details":{"type":"string"}},"required":["src"],"additionalProperties":false}}},"required":["images"],"additionalProperties":false,"description":"Gallery grid of images with modal preview"},"Separator":{"type":"object","properties":{"orientation":{"type":"string","enum":["horizontal","vertical"]},"decorative":{"type":"boolean"}},"additionalProperties":false,"description":"Visual divider between content sections"},"HorizontalBarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["grouped","stacked"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"}},"required":["labels","series"],"additionalProperties":false,"description":"Horizontal bars; prefer when category labels are long or for ranked lists"},"Series":{"type":"object","properties":{"category":{"type":"string"},"values":{"type":"array","items":{"type":"number"}}},"required":["category","values"],"additionalProperties":false,"description":"One data series"},"RadarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}}},"required":["labels","series"],"additionalProperties":false,"description":"Spider/web chart; use for comparing multiple variables across one or more entities"},"PieChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}},"variant":{"type":"string","enum":["pie","donut"]},"appearance":{"type":"string","enum":["circular","semiCircular"]}},"required":["labels","values"],"additionalProperties":false,"description":"Circular slices; use plucked arrays: PieChart(data.categories, data.values)"},"RadialChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}}},"required":["labels","values"],"additionalProperties":false,"description":"Radial bars; use plucked arrays: RadialChart(data.categories, data.values)"},"SingleStackedBarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}}},"required":["labels","values"],"additionalProperties":false,"description":"Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)"},"ScatterChart":{"type":"object","properties":{"datasets":{"type":"array","items":{"$ref":"#/$defs/ScatterSeries"}},"xLabel":{"type":"string"},"yLabel":{"type":"string"}},"required":["datasets"],"additionalProperties":false,"description":"X/Y scatter plot; use for correlations, distributions, and clustering"},"ScatterSeries":{"type":"object","properties":{"name":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/$defs/Point"}}},"required":["name","points"],"additionalProperties":false,"description":"Named dataset"},"Point":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}},"required":["x","y"],"additionalProperties":false,"description":"Data point with numeric coordinates"},"AreaChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["linear","natural","step"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Filled area under lines; use for cumulative totals or volume trends over time"},"BarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["grouped","stacked"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Vertical bars; use for comparing values across categories with one or more series"},"LineChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["linear","natural","step"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Lines over categories; use for trends and continuous data over time"},"Table":{"type":"object","properties":{"columns":{"type":"array","items":{"$ref":"#/$defs/Col"}}},"required":["columns"],"additionalProperties":false,"description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"type":"object","properties":{"label":{"type":"string"},"data":{},"type":{"type":"string","enum":["string","number","action"]}},"required":["label","data"],"additionalProperties":false,"description":"Column definition — holds label + data array"},"TagBlock":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"}},"size":{"type":"string","enum":["sm","md","lg"]}},"required":["tags"],"additionalProperties":false,"description":"tags is an array of strings; optional size sm | md | lg"},"Form":{"type":"object","properties":{"name":{"type":"string"},"buttons":{"$ref":"#/$defs/Buttons"},"fields":{"default":[],"type":"array","items":{"$ref":"#/$defs/FormControl"}}},"required":["name","buttons","fields"],"additionalProperties":false,"description":"Form container with fields and explicit action buttons"},"Buttons":{"type":"object","properties":{"buttons":{"type":"array","items":{"$ref":"#/$defs/Button"}},"direction":{"type":"string","enum":["row","column"]}},"required":["buttons"],"additionalProperties":false,"description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"Button":{"type":"object","properties":{"label":{"type":"string"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"variant":{"type":"string","enum":["primary","secondary","tertiary"]},"type":{"type":"string","enum":["normal","destructive"]},"size":{"type":"string","enum":["extra-small","small","medium","large"]}},"required":["label"],"additionalProperties":false,"description":"Clickable button"},"FormControl":{"type":"object","properties":{"label":{"type":"string"},"input":{"anyOf":[{"$ref":"#/$defs/Input"},{"$ref":"#/$defs/TextArea"},{"$ref":"#/$defs/Select"},{"$ref":"#/$defs/DatePicker"},{"$ref":"#/$defs/Slider"},{"$ref":"#/$defs/CheckBoxGroup"},{"$ref":"#/$defs/RadioGroup"},{"$ref":"#/$defs/Chips"},{"$ref":"#/$defs/OptionCards"}]},"hint":{"type":"string"}},"required":["label","input"],"additionalProperties":false,"description":"Field with label, input component, and optional hint text"},"Input":{"type":"object","properties":{"name":{"type":"string"},"placeholder":{"type":"string"},"type":{"type":"string","enum":["text","email","password","number","url"]},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name"],"additionalProperties":false},"TextArea":{"type":"object","properties":{"name":{"type":"string"},"placeholder":{"type":"string"},"rows":{"type":"number"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name"],"additionalProperties":false},"Select":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/SelectItem"}},"placeholder":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"},"size":{"type":"string","enum":["small","medium","large"]}},"required":["name","items"],"additionalProperties":false},"SelectItem":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}},"required":["value","label"],"additionalProperties":false,"description":"Option for Select"},"DatePicker":{"type":"object","properties":{"name":{"type":"string"},"mode":{"type":"string","enum":["single","range"]},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{}},"required":["name"],"additionalProperties":false},"Slider":{"type":"object","properties":{"name":{"type":"string"},"variant":{"type":"string","enum":["continuous","discrete"]},"min":{"type":"number"},"max":{"type":"number"},"step":{"type":"number"},"defaultValue":{"type":"array","items":{"type":"number"}},"label":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"array","items":{"type":"number"}}},"required":["name","variant","min","max"],"additionalProperties":false,"description":"Numeric slider input; supports continuous and discrete (stepped) variants"},"CheckBoxGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/CheckBoxItem"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"boolean"}}},"required":["name","items"],"additionalProperties":false},"CheckBoxItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"},"defaultChecked":{"type":"boolean"}},"required":["label","description","name"],"additionalProperties":false},"RadioGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/RadioItem"}},"defaultValue":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name","items"],"additionalProperties":false},"RadioItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"value":{"type":"string"}},"required":["label","description","value"],"additionalProperties":false},"Chips":{"type":"object","properties":{"name":{"type":"string"},"type":{"default":"multiple","type":"string","enum":["single","multiple"]},"items":{"default":[],"type":"array","items":{"$ref":"#/$defs/ChipItem"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"defaultValue":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}},"required":["name","type","items"],"additionalProperties":false,"description":"A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`."},"ChipItem":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"disabled":{"type":"boolean"}},"required":["value","label"],"additionalProperties":false,"description":"A single selectable chip inside a Chips group, with a value, label and optional icon."},"Icon":{"type":"object","properties":{"name":{"type":"string"},"category":{"type":"string"}},"required":["name"],"additionalProperties":false,"description":"A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve."},"OptionCards":{"type":"object","properties":{"name":{"type":"string"},"type":{"default":"single","type":"string","enum":["single","multiple"]},"items":{"default":[],"type":"array","items":{"$ref":"#/$defs/OptionCard"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"defaultValue":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}},"required":["name","type","items"],"additionalProperties":false,"description":"A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`."},"OptionCard":{"type":"object","properties":{"value":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"topContent":{"anyOf":[{"$ref":"#/$defs/Icon"},{"$ref":"#/$defs/Image"}]},"disabled":{"type":"boolean"}},"required":["value","title"],"additionalProperties":false,"description":"A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top."},"IconButton":{"type":"object","properties":{"name":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"variant":{"type":"string","enum":["primary","secondary","tertiary"]},"size":{"type":"string","enum":["extra-small","small","medium","large"]},"shape":{"type":"string","enum":["square","circle"]}},"required":["name","icon"],"additionalProperties":false,"description":"Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click."},"Steps":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/StepsItem"}}},"required":["items"],"additionalProperties":false,"description":"Step-by-step guide"},"StepsItem":{"type":"object","properties":{"title":{"type":"string"},"details":{"type":"string"}},"required":["title","details"],"additionalProperties":false,"description":"title and details text for one step"},"InlineHeader":{"type":"object","properties":{"heading":{"type":"string"},"description":{"type":"string"}},"required":["heading"],"additionalProperties":false,"description":"Compact section heading with an optional one-line description, for use inside cards."},"EntityList":{"type":"object","properties":{"rows":{"default":[],"type":"array","items":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false}},"size":{"default":"default","type":"string","enum":["small","default"]},"header":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false},"footer":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false}},"required":["rows","size"],"additionalProperties":false,"description":"Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers."},"EditableTable":{"type":"object","properties":{"name":{"default":"","type":"string"},"columns":{"default":[],"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["text","number","date-single","select","url"]},"key":{"default":"default","type":"string"},"header":{"default":"","type":"string"},"width":{"type":"number"},"options":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}},"required":["value","label"],"additionalProperties":false}}},"required":["type","key","header"],"additionalProperties":false}},"data":{"default":[],"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"values":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}}},"required":["id","values"],"additionalProperties":false}}},"required":["name","columns","data"],"additionalProperties":false,"description":"Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field"},"SnippetCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/SnippetCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action."},"SnippetCardItem":{"type":"object","properties":{"id":{"type":"string"},"lhs":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"}]},"rhs":{"anyOf":[{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/BoldText"}]}},"required":["lhs"],"additionalProperties":false,"description":"One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)."},"IconText":{"type":"object","properties":{"icon":{"$ref":"#/$defs/Icon"},"iconVariant":{"default":"neutral","type":"string","enum":["neutral","info","success","warning","danger","inverted","filled","soft"]},"iconSize":{"default":"m","type":"string","enum":["xs","s","m","l","xl","sm","md","lg"]},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"},"layout":{"default":"horizontal","type":"string","enum":["horizontal","vertical"]}},"required":["icon","iconVariant","iconSize","title","bold","layout"],"additionalProperties":false,"description":"An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color."},"ImageText":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"},"layout":{"default":"horizontal","type":"string","enum":["horizontal","vertical"]},"imageSize":{"type":"number"}},"required":["src","title","bold","layout"],"additionalProperties":false,"description":"A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL."},"Text":{"type":"object","properties":{"variant":{"default":"text","type":"string","enum":["text","number"]},"value":{"type":"string"},"subtext":{"type":"string"},"subtextVariant":{"default":"text","type":"string","enum":["text","number","metric"]},"size":{"default":"sm","type":"string","enum":["xs","sm","md","lg"]}},"required":["variant","value","subtextVariant","size"],"additionalProperties":false,"description":"Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"BoldText":{"type":"object","properties":{"variant":{"default":"text","type":"string","enum":["text","number"]},"value":{"type":"string"},"subtext":{"type":"string"},"subtextVariant":{"default":"text","type":"string","enum":["text","number","metric"]},"size":{"default":"sm","type":"string","enum":["xs","sm","md","lg"]}},"required":["variant","value","subtextVariant","size"],"additionalProperties":false,"description":"Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"OverviewCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/OverviewCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action."},"OverviewCardItem":{"type":"object","properties":{"id":{"type":"string"},"top":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"},{"$ref":"#/$defs/Text"}]},"bottom":{"$ref":"#/$defs/MetricIndicatorInline"}},"required":["top"],"additionalProperties":false,"description":"One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom."},"MetricIndicatorInline":{"type":"object","properties":{"value":{"type":"string"},"subtext":{"type":"string"},"trend":{"type":"object","properties":{"direction":{"type":"string","enum":["up","down"]},"value":{"type":"number"}},"required":["direction","value"],"additionalProperties":false}},"required":["value"],"additionalProperties":false,"description":"Headline metric value with an optional +/- percentage trend and subtext, all on one line."},"ContextCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/ContextCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable."},"ContextCardItem":{"type":"object","properties":{"id":{"type":"string"},"title":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/Tag"}]},"body":{"type":"string"},"bgColor":{"type":"string","enum":["gray"]},"bgImageSrc":{"type":"string"},"bgImageAlt":{"type":"string"}},"required":["title"],"additionalProperties":false,"description":"A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image."},"Tag":{"type":"object","properties":{"text":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"size":{"type":"string","enum":["sm","md","lg"]},"variant":{"type":"string","enum":["neutral","info","success","warning","danger"]}},"required":["text"],"additionalProperties":false,"description":"Styled tag/badge with optional Icon and variant"},"CompositeCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/CompositeCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable."},"CompositeCardItem":{"type":"object","properties":{"id":{"type":"string"},"header":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"},{"$ref":"#/$defs/ImageTextLarge"},{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/Image"}]},"body":{"default":[],"type":"array","items":{"anyOf":[{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/BoldText"},{"$ref":"#/$defs/MetricIndicatorInline"},{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/ListBlock"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/EntityList"}]}},"footer":{"type":"object","properties":{"price":{"anyOf":[{"$ref":"#/$defs/BoldText"},{"$ref":"#/$defs/MetricIndicatorWithStrikethrough"}]},"button":{"$ref":"#/$defs/Button"}},"additionalProperties":false}},"required":["body"],"additionalProperties":false,"description":"A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer."},"ImageTextLarge":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"}},"required":["src","title","bold"],"additionalProperties":false,"description":"A full-width banner image above a bold title and optional subtitle. src must be a real image URL."},"ListBlock":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/ListItem"}},"variant":{"type":"string","enum":["number","image"]},"size":{"type":"string","enum":["default","small"]}},"required":["items"],"additionalProperties":false,"description":"A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list."},"ListItem":{"type":"object","properties":{"title":{"type":"string"},"subtitle":{"type":"string"},"image":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"}},"required":["src","alt"],"additionalProperties":false},"actionLabel":{"type":"string"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]}},"required":["title"],"additionalProperties":false,"description":"Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable."},"MetricIndicatorWithStrikethrough":{"type":"object","properties":{"value":{"type":"string"},"subtext":{"type":"string"},"previousValue":{"type":"string"},"trend":{"type":"object","properties":{"direction":{"type":"string","enum":["up","down"]},"value":{"type":"number"}},"required":["direction","value"],"additionalProperties":false}},"required":["value"],"additionalProperties":false,"description":"Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below."},"VisualCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/VisualCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable."},"VisualCardItem":{"type":"object","properties":{"body":{"$ref":"#/$defs/BoldText"},"id":{"type":"string"},"bgImageSrc":{"type":"string"},"tag":{"$ref":"#/$defs/Tag"},"bgImageAlt":{"type":"string"}},"required":["body"],"additionalProperties":false,"description":"A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)."},"Tabs":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/TabItem"}}},"required":["items"],"additionalProperties":false,"description":"Tabbed container"},"TabItem":{"type":"object","properties":{"value":{"type":"string"},"trigger":{"type":"string"},"content":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}}},"required":["value","trigger","content"],"additionalProperties":false,"description":"value is unique id, trigger is tab label, content is array of components"},"Carousel":{"type":"object","properties":{"children":{"type":"array","items":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}}},"variant":{"type":"string","enum":["card","sunk"]}},"required":["children"],"additionalProperties":false,"description":"Horizontal scrollable carousel"},"Stack":{"type":"object","properties":{"children":{"type":"array","items":{}},"direction":{"type":"string","enum":["row","column"]},"gap":{"type":"string","enum":["none","xs","s","m","l","xl","2xl"]},"align":{"type":"string","enum":["start","center","end","stretch","baseline"]},"justify":{"type":"string","enum":["start","center","end","between","around","evenly"]},"wrap":{"type":"boolean"}},"required":["children"],"additionalProperties":false,"description":"Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"."},"Slice":{"type":"object","properties":{"category":{"type":"string"},"value":{"type":"number"}},"required":["category","value"],"additionalProperties":false,"description":"One slice with label and numeric value"},"Label":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"],"additionalProperties":false,"description":"Text label"},"SwitchGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/SwitchItem"}},"variant":{"type":"string","enum":["clear","card","sunk"]},"value":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"boolean"}}},"required":["name","items"],"additionalProperties":false,"description":"Group of switch toggles"},"SwitchItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"},"defaultChecked":{"type":"boolean"}},"required":["name"],"additionalProperties":false,"description":"Individual switch toggle"},"Accordion":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/AccordionItem"}}},"required":["items"],"additionalProperties":false,"description":"Collapsible sections"},"AccordionItem":{"type":"object","properties":{"value":{"type":"string"},"trigger":{"type":"string"},"content":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}}},"required":["value","trigger","content"],"additionalProperties":false,"description":"value is unique id, trigger is section title"},"Modal":{"type":"object","properties":{"title":{"type":"string"},"open":{"type":"boolean"},"children":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}},"size":{"type":"string","enum":["sm","md","lg"]}},"required":["title","children"],"additionalProperties":false,"description":"Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children."}}}},"expected":"You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Stack(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Layout\nStack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean) — Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\".\nTabs(items: TabItem[]) — Tabbed container\nTabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[]) — value is unique id, trigger is tab label, content is array of components\nAccordion(items: AccordionItem[]) — Collapsible sections\nAccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[]) — value is unique id, trigger is section title\nSteps(items: StepsItem[]) — Step-by-step guide\nStepsItem(title: string, details: string) — title and details text for one step\nCarousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\") — Horizontal scrollable carousel\nSeparator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean) — Visual divider between content sections\nModal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\") — Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children.\n- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.\n- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.\n- Use nested Stacks when you need explicit rows/sections.\n- Show/hide sections: $editId != \"\" ? Card([editForm]) : null\n- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.\n- Use Tabs for alternative views (chart types, data sections) — no $variable needed\n- Shared filter across Tabs: same $days binding in Query args works across all TabItems\n\n### Content\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean) — Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts.\nCardHeader(title?: string, subtitle?: string) — Header with optional title and subtitle\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nMarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\") — Renders markdown text with optional container variant\nCallout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding) — Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.\nTextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string) — Text callout with variant, title, and description\nImage(alt: string, src?: string) — Image with alt text and optional URL\nImageBlock(src: string, alt?: string) — Image block with loading state\nImageGallery(images: {src: string, alt?: string, details?: string}[]) — Gallery grid of images with modal preview\nCodeBlock(language: string, codeString: string) — Syntax-highlighted code block\nInlineHeader(heading: string, description?: string) — Compact section heading with an optional one-line description, for use inside cards.\n- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).\n- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.\n- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null\n- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])\n\n### Tables\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\nEditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[]) — Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field\n- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).\n- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.\n- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName\n- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))\n- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))\n- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data\n- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input\n- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts\n- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")\n\n### Charts (2D)\nBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number) — Vertical bars; use for comparing values across categories with one or more series\nLineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Lines over categories; use for trends and continuous data over time\nAreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Filled area under lines; use for cumulative totals or volume trends over time\nRadarChart(labels: string[], series: Series[]) — Spider/web chart; use for comparing multiple variables across one or more entities\nHorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string) — Horizontal bars; prefer when category labels are long or for ranked lists\nSeries(category: string, values: number[]) — One data series\n- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])\n- Use Cards to wrap charts with CardHeader for titled sections\n- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data\n- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])\n\n### Charts (1D)\nPieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\") — Circular slices; use plucked arrays: PieChart(data.categories, data.values)\nRadialChart(labels: string[], values: number[]) — Radial bars; use plucked arrays: RadialChart(data.categories, data.values)\nSingleStackedBarChart(labels: string[], values: number[]) — Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)\nSlice(category: string, value: number) — One slice with label and numeric value\n- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:\n- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`\n- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`\n\n### Charts (Scatter)\nScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string) — X/Y scatter plot; use for correlations, distributions, and clustering\nScatterSeries(name: string, points: Point[]) — Named dataset\nPoint(x: number, y: number, z?: number) — Data point with numeric coordinates\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nLabel(text: string) — Text label\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nTextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nDatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSlider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding) — Numeric slider input; supports continuous and discrete (stepped) variants\nCheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)\nCheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)\nRadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nRadioItem(label: string, description: string, value: string)\nSwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>) — Group of switch toggles\nSwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean) — Individual switch toggle\nChips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.\nChipItem(value: string, label: string, icon?: Icon, disabled?: boolean) — A single selectable chip inside a Chips group, with a value, label and optional icon.\nOptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.\nOptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean) — A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.\n- Chips: compact single/multiple selection pills. Use ChipItem references for each option.\n- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.\n- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.\n- NEVER nest Form inside Form — each Form should be a standalone container.\n- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.\n- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}\n- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric\n- The renderer shows error messages automatically — do NOT generate error text in the UI\n- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField\n- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal.\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nIconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\") — Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.\n- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.\n- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))\n\n### Data Display\nTagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\") — tags is an array of strings; optional size sm | md | lg\nTag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\") — Styled tag/badge with optional Icon and variant\nIcon(name: string, category?: string) — A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.\nEntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}) — Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.\nListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\") — A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.\nListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression) — Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.\n- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")\n- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.\n- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional.\n\n### Cards\nSnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.\nSnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText) — One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).\nOverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.\nOverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline) — One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.\nContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.\nContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string) — A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.\nCompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.\nCompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button}) — A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.\nVisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.\nVisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string) — A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).\nText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nBoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nIconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\") — An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.\nImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number) — A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.\nImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean) — A full-width banner image above a bold title and optional subtitle. src must be a real image URL.\nMetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional +/- percentage trend and subtext, all on one line.\nMetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.\n- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.\n- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.\n- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.\n- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.\n- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.\n- VisualCardItem: image-first card with a BoldText body and optional Tag.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Stack(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Stack(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Stack(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root."}, +{"name":"openui-options","spec":{"root":"Stack","components":{"Card":{"signature":"Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)","description":"Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts."},"CardHeader":{"signature":"CardHeader(title?: string, subtitle?: string)","description":"Header with optional title and subtitle"},"TextContent":{"signature":"TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")","description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"MarkDownRenderer":{"signature":"MarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\")","description":"Renders markdown text with optional container variant"},"Callout":{"signature":"Callout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding)","description":"Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false."},"TextCallout":{"signature":"TextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string)","description":"Text callout with variant, title, and description"},"Image":{"signature":"Image(alt: string, src?: string)","description":"Image with alt text and optional URL"},"ImageBlock":{"signature":"ImageBlock(src: string, alt?: string)","description":"Image block with loading state"},"ImageGallery":{"signature":"ImageGallery(images: {src: string, alt?: string, details?: string}[])","description":"Gallery grid of images with modal preview"},"CodeBlock":{"signature":"CodeBlock(language: string, codeString: string)","description":"Syntax-highlighted code block"},"InlineHeader":{"signature":"InlineHeader(heading: string, description?: string)","description":"Compact section heading with an optional one-line description, for use inside cards."},"Table":{"signature":"Table(columns: Col[])","description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"signature":"Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")","description":"Column definition — holds label + data array"},"EditableTable":{"signature":"EditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[])","description":"Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field"},"BarChart":{"signature":"BarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number)","description":"Vertical bars; use for comparing values across categories with one or more series"},"LineChart":{"signature":"LineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)","description":"Lines over categories; use for trends and continuous data over time"},"AreaChart":{"signature":"AreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number)","description":"Filled area under lines; use for cumulative totals or volume trends over time"},"RadarChart":{"signature":"RadarChart(labels: string[], series: Series[])","description":"Spider/web chart; use for comparing multiple variables across one or more entities"},"HorizontalBarChart":{"signature":"HorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string)","description":"Horizontal bars; prefer when category labels are long or for ranked lists"},"Series":{"signature":"Series(category: string, values: number[])","description":"One data series"},"PieChart":{"signature":"PieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\")","description":"Circular slices; use plucked arrays: PieChart(data.categories, data.values)"},"RadialChart":{"signature":"RadialChart(labels: string[], values: number[])","description":"Radial bars; use plucked arrays: RadialChart(data.categories, data.values)"},"SingleStackedBarChart":{"signature":"SingleStackedBarChart(labels: string[], values: number[])","description":"Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)"},"Slice":{"signature":"Slice(category: string, value: number)","description":"One slice with label and numeric value"},"ScatterChart":{"signature":"ScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string)","description":"X/Y scatter plot; use for correlations, distributions, and clustering"},"ScatterSeries":{"signature":"ScatterSeries(name: string, points: Point[])","description":"Named dataset"},"Point":{"signature":"Point(x: number, y: number, z?: number)","description":"Data point with numeric coordinates"},"Form":{"signature":"Form(name: string, buttons: Buttons, fields?: FormControl[])","description":"Form container with fields and explicit action buttons"},"FormControl":{"signature":"FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)","description":"Field with label, input component, and optional hint text"},"Label":{"signature":"Label(text: string)","description":"Text label"},"Input":{"signature":"Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"TextArea":{"signature":"TextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Select":{"signature":"Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")","description":""},"SelectItem":{"signature":"SelectItem(value: string, label: string)","description":"Option for Select"},"DatePicker":{"signature":"DatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Slider":{"signature":"Slider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":"Numeric slider input; supports continuous and discrete (stepped) variants"},"CheckBoxGroup":{"signature":"CheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)","description":""},"CheckBoxItem":{"signature":"CheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)","description":""},"RadioGroup":{"signature":"RadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"RadioItem":{"signature":"RadioItem(label: string, description: string, value: string)","description":""},"SwitchGroup":{"signature":"SwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>)","description":"Group of switch toggles"},"SwitchItem":{"signature":"SwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean)","description":"Individual switch toggle"},"ChipItem":{"signature":"ChipItem(value: string, label: string, icon?: Icon, disabled?: boolean)","description":"A single selectable chip inside a Chips group, with a value, label and optional icon."},"Chips":{"signature":"Chips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])","description":"A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`."},"OptionCard":{"signature":"OptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean)","description":"A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top."},"OptionCards":{"signature":"OptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[])","description":"A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`."},"Button":{"signature":"Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")","description":"Clickable button"},"Buttons":{"signature":"Buttons(buttons: Button[], direction?: \"row\" | \"column\")","description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"IconButton":{"signature":"IconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\")","description":"Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click."},"Stack":{"signature":"Stack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean)","description":"Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"."},"Tabs":{"signature":"Tabs(items: TabItem[])","description":"Tabbed container"},"TabItem":{"signature":"TabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])","description":"value is unique id, trigger is tab label, content is array of components"},"Accordion":{"signature":"Accordion(items: AccordionItem[])","description":"Collapsible sections"},"AccordionItem":{"signature":"AccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[])","description":"value is unique id, trigger is section title"},"Steps":{"signature":"Steps(items: StepsItem[])","description":"Step-by-step guide"},"StepsItem":{"signature":"StepsItem(title: string, details: string)","description":"title and details text for one step"},"Carousel":{"signature":"Carousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\")","description":"Horizontal scrollable carousel"},"Separator":{"signature":"Separator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean)","description":"Visual divider between content sections"},"TagBlock":{"signature":"TagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\")","description":"tags is an array of strings; optional size sm | md | lg"},"Tag":{"signature":"Tag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\")","description":"Styled tag/badge with optional Icon and variant"},"Icon":{"signature":"Icon(name: string, category?: string)","description":"A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve."},"EntityList":{"signature":"EntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"})","description":"Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers."},"ListBlock":{"signature":"ListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\")","description":"A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list."},"ListItem":{"signature":"ListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression)","description":"Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable."},"Text":{"signature":"Text(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")","description":"Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"BoldText":{"signature":"BoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\")","description":"Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"IconText":{"signature":"IconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\")","description":"An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color."},"ImageText":{"signature":"ImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number)","description":"A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL."},"ImageTextLarge":{"signature":"ImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean)","description":"A full-width banner image above a bold title and optional subtitle. src must be a real image URL."},"MetricIndicatorInline":{"signature":"MetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number})","description":"Headline metric value with an optional +/- percentage trend and subtext, all on one line."},"MetricIndicatorWithStrikethrough":{"signature":"MetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number})","description":"Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below."},"SnippetCardItem":{"signature":"SnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText)","description":"One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)."},"SnippetCardBlock":{"signature":"SnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action."},"OverviewCardItem":{"signature":"OverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline)","description":"One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom."},"OverviewCardBlock":{"signature":"OverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action."},"ContextCardItem":{"signature":"ContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string)","description":"A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image."},"ContextCardBlock":{"signature":"ContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable."},"CompositeCardItem":{"signature":"CompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button})","description":"A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer."},"CompositeCardBlock":{"signature":"CompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable."},"VisualCardItem":{"signature":"VisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string)","description":"A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)."},"VisualCardBlock":{"signature":"VisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string)","description":"A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable."},"Modal":{"signature":"Modal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\")","description":"Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children."}},"componentGroups":[{"name":"Layout","components":["Stack","Tabs","TabItem","Accordion","AccordionItem","Steps","StepsItem","Carousel","Separator","Modal"],"notes":["- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.","- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.","- Use nested Stacks when you need explicit rows/sections.","- Show/hide sections: $editId != \"\" ? Card([editForm]) : null","- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.","- Use Tabs for alternative views (chart types, data sections) — no $variable needed","- Shared filter across Tabs: same $days binding in Query args works across all TabItems"]},{"name":"Content","components":["Card","CardHeader","TextContent","MarkDownRenderer","Callout","TextCallout","Image","ImageBlock","ImageGallery","CodeBlock","InlineHeader"],"notes":["- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).","- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.","- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null","- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])"]},{"name":"Tables","components":["Table","Col","EditableTable"],"notes":["- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).","- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.","- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName","- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))","- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))","- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data","- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input","- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts","- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")"]},{"name":"Charts (2D)","components":["BarChart","LineChart","AreaChart","RadarChart","HorizontalBarChart","Series"],"notes":["- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])","- Use Cards to wrap charts with CardHeader for titled sections","- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data","- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])"]},{"name":"Charts (1D)","components":["PieChart","RadialChart","SingleStackedBarChart","Slice"],"notes":["- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:","- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`","- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`"]},{"name":"Charts (Scatter)","components":["ScatterChart","ScatterSeries","Point"]},{"name":"Forms","components":["Form","FormControl","Label","Input","TextArea","Select","SelectItem","DatePicker","Slider","CheckBoxGroup","CheckBoxItem","RadioGroup","RadioItem","SwitchGroup","SwitchItem","Chips","ChipItem","OptionCards","OptionCard"],"notes":["- Chips: compact single/multiple selection pills. Use ChipItem references for each option.","- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.","- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.","- NEVER nest Form inside Form — each Form should be a standalone container.","- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.","- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}","- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric","- The renderer shows error messages automatically — do NOT generate error text in the UI","- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField","- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal."]},{"name":"Buttons","components":["Button","Buttons","IconButton"],"notes":["- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.","- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))"]},{"name":"Data Display","components":["TagBlock","Tag","Icon","EntityList","ListBlock","ListItem"],"notes":["- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")","- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.","- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional."]},{"name":"Cards","components":["SnippetCardBlock","SnippetCardItem","OverviewCardBlock","OverviewCardItem","ContextCardBlock","ContextCardItem","CompositeCardBlock","CompositeCardItem","VisualCardBlock","VisualCardItem","Text","BoldText","IconText","ImageText","ImageTextLarge","MetricIndicatorInline","MetricIndicatorWithStrikethrough"],"notes":["- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.","- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.","- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.","- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.","- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.","- VisualCardItem: image-first card with a BoldText body and optional Tag.","- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card."]}],"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"Card":{"$ref":"#/$defs/Card"},"CardHeader":{"$ref":"#/$defs/CardHeader"},"TextContent":{"$ref":"#/$defs/TextContent"},"MarkDownRenderer":{"$ref":"#/$defs/MarkDownRenderer"},"Callout":{"$ref":"#/$defs/Callout"},"TextCallout":{"$ref":"#/$defs/TextCallout"},"Image":{"$ref":"#/$defs/Image"},"ImageBlock":{"$ref":"#/$defs/ImageBlock"},"ImageGallery":{"$ref":"#/$defs/ImageGallery"},"CodeBlock":{"$ref":"#/$defs/CodeBlock"},"InlineHeader":{"$ref":"#/$defs/InlineHeader"},"Table":{"$ref":"#/$defs/Table"},"Col":{"$ref":"#/$defs/Col"},"EditableTable":{"$ref":"#/$defs/EditableTable"},"BarChart":{"$ref":"#/$defs/BarChart"},"LineChart":{"$ref":"#/$defs/LineChart"},"AreaChart":{"$ref":"#/$defs/AreaChart"},"RadarChart":{"$ref":"#/$defs/RadarChart"},"HorizontalBarChart":{"$ref":"#/$defs/HorizontalBarChart"},"Series":{"$ref":"#/$defs/Series"},"PieChart":{"$ref":"#/$defs/PieChart"},"RadialChart":{"$ref":"#/$defs/RadialChart"},"SingleStackedBarChart":{"$ref":"#/$defs/SingleStackedBarChart"},"Slice":{"$ref":"#/$defs/Slice"},"ScatterChart":{"$ref":"#/$defs/ScatterChart"},"ScatterSeries":{"$ref":"#/$defs/ScatterSeries"},"Point":{"$ref":"#/$defs/Point"},"Form":{"$ref":"#/$defs/Form"},"FormControl":{"$ref":"#/$defs/FormControl"},"Label":{"$ref":"#/$defs/Label"},"Input":{"$ref":"#/$defs/Input"},"TextArea":{"$ref":"#/$defs/TextArea"},"Select":{"$ref":"#/$defs/Select"},"SelectItem":{"$ref":"#/$defs/SelectItem"},"DatePicker":{"$ref":"#/$defs/DatePicker"},"Slider":{"$ref":"#/$defs/Slider"},"CheckBoxGroup":{"$ref":"#/$defs/CheckBoxGroup"},"CheckBoxItem":{"$ref":"#/$defs/CheckBoxItem"},"RadioGroup":{"$ref":"#/$defs/RadioGroup"},"RadioItem":{"$ref":"#/$defs/RadioItem"},"SwitchGroup":{"$ref":"#/$defs/SwitchGroup"},"SwitchItem":{"$ref":"#/$defs/SwitchItem"},"ChipItem":{"$ref":"#/$defs/ChipItem"},"Chips":{"$ref":"#/$defs/Chips"},"OptionCard":{"$ref":"#/$defs/OptionCard"},"OptionCards":{"$ref":"#/$defs/OptionCards"},"Button":{"$ref":"#/$defs/Button"},"Buttons":{"$ref":"#/$defs/Buttons"},"IconButton":{"$ref":"#/$defs/IconButton"},"Stack":{"$ref":"#/$defs/Stack"},"Tabs":{"$ref":"#/$defs/Tabs"},"TabItem":{"$ref":"#/$defs/TabItem"},"Accordion":{"$ref":"#/$defs/Accordion"},"AccordionItem":{"$ref":"#/$defs/AccordionItem"},"Steps":{"$ref":"#/$defs/Steps"},"StepsItem":{"$ref":"#/$defs/StepsItem"},"Carousel":{"$ref":"#/$defs/Carousel"},"Separator":{"$ref":"#/$defs/Separator"},"TagBlock":{"$ref":"#/$defs/TagBlock"},"Tag":{"$ref":"#/$defs/Tag"},"Icon":{"$ref":"#/$defs/Icon"},"EntityList":{"$ref":"#/$defs/EntityList"},"ListBlock":{"$ref":"#/$defs/ListBlock"},"ListItem":{"$ref":"#/$defs/ListItem"},"Text":{"$ref":"#/$defs/Text"},"BoldText":{"$ref":"#/$defs/BoldText"},"IconText":{"$ref":"#/$defs/IconText"},"ImageText":{"$ref":"#/$defs/ImageText"},"ImageTextLarge":{"$ref":"#/$defs/ImageTextLarge"},"MetricIndicatorInline":{"$ref":"#/$defs/MetricIndicatorInline"},"MetricIndicatorWithStrikethrough":{"$ref":"#/$defs/MetricIndicatorWithStrikethrough"},"SnippetCardItem":{"$ref":"#/$defs/SnippetCardItem"},"SnippetCardBlock":{"$ref":"#/$defs/SnippetCardBlock"},"OverviewCardItem":{"$ref":"#/$defs/OverviewCardItem"},"OverviewCardBlock":{"$ref":"#/$defs/OverviewCardBlock"},"ContextCardItem":{"$ref":"#/$defs/ContextCardItem"},"ContextCardBlock":{"$ref":"#/$defs/ContextCardBlock"},"CompositeCardItem":{"$ref":"#/$defs/CompositeCardItem"},"CompositeCardBlock":{"$ref":"#/$defs/CompositeCardBlock"},"VisualCardItem":{"$ref":"#/$defs/VisualCardItem"},"VisualCardBlock":{"$ref":"#/$defs/VisualCardBlock"},"Modal":{"$ref":"#/$defs/Modal"}},"required":["Card","CardHeader","TextContent","MarkDownRenderer","Callout","TextCallout","Image","ImageBlock","ImageGallery","CodeBlock","InlineHeader","Table","Col","EditableTable","BarChart","LineChart","AreaChart","RadarChart","HorizontalBarChart","Series","PieChart","RadialChart","SingleStackedBarChart","Slice","ScatterChart","ScatterSeries","Point","Form","FormControl","Label","Input","TextArea","Select","SelectItem","DatePicker","Slider","CheckBoxGroup","CheckBoxItem","RadioGroup","RadioItem","SwitchGroup","SwitchItem","ChipItem","Chips","OptionCard","OptionCards","Button","Buttons","IconButton","Stack","Tabs","TabItem","Accordion","AccordionItem","Steps","StepsItem","Carousel","Separator","TagBlock","Tag","Icon","EntityList","ListBlock","ListItem","Text","BoldText","IconText","ImageText","ImageTextLarge","MetricIndicatorInline","MetricIndicatorWithStrikethrough","SnippetCardItem","SnippetCardBlock","OverviewCardItem","OverviewCardBlock","ContextCardItem","ContextCardBlock","CompositeCardItem","CompositeCardBlock","VisualCardItem","VisualCardBlock","Modal"],"additionalProperties":false,"$defs":{"Card":{"type":"object","properties":{"children":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"},{"$ref":"#/$defs/Tabs"},{"$ref":"#/$defs/Carousel"},{"$ref":"#/$defs/Stack"}]}},"variant":{"type":"string","enum":["card","sunk","clear"]},"direction":{"type":"string","enum":["row","column"]},"gap":{"type":"string","enum":["none","xs","s","m","l","xl","2xl"]},"align":{"type":"string","enum":["start","center","end","stretch","baseline"]},"justify":{"type":"string","enum":["start","center","end","between","around","evenly"]},"wrap":{"type":"boolean"}},"required":["children"],"additionalProperties":false,"description":"Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts."},"TextContent":{"type":"object","properties":{"text":{"type":"string"},"size":{"type":"string","enum":["small","default","large","small-heavy","large-heavy"]}},"required":["text"],"additionalProperties":false,"description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"MarkDownRenderer":{"type":"object","properties":{"textMarkdown":{"type":"string"},"variant":{"type":"string","enum":["clear","card","sunk"]}},"required":["textMarkdown"],"additionalProperties":false,"description":"Renders markdown text with optional container variant"},"CardHeader":{"type":"object","properties":{"title":{"type":"string"},"subtitle":{"type":"string"}},"additionalProperties":false,"description":"Header with optional title and subtitle"},"Callout":{"type":"object","properties":{"variant":{"type":"string","enum":["info","warning","error","success","neutral"]},"title":{"type":"string"},"description":{"type":"string"},"visible":{"type":"boolean"}},"required":["variant","title","description"],"additionalProperties":false,"description":"Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false."},"TextCallout":{"type":"object","properties":{"variant":{"type":"string","enum":["neutral","info","warning","success","danger"]},"title":{"type":"string"},"description":{"type":"string"}},"additionalProperties":false,"description":"Text callout with variant, title, and description"},"CodeBlock":{"type":"object","properties":{"language":{"type":"string"},"codeString":{"type":"string"}},"required":["language","codeString"],"additionalProperties":false,"description":"Syntax-highlighted code block"},"Image":{"type":"object","properties":{"alt":{"type":"string"},"src":{"type":"string"}},"required":["alt"],"additionalProperties":false,"description":"Image with alt text and optional URL"},"ImageBlock":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"}},"required":["src"],"additionalProperties":false,"description":"Image block with loading state"},"ImageGallery":{"type":"object","properties":{"images":{"type":"array","items":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"details":{"type":"string"}},"required":["src"],"additionalProperties":false}}},"required":["images"],"additionalProperties":false,"description":"Gallery grid of images with modal preview"},"Separator":{"type":"object","properties":{"orientation":{"type":"string","enum":["horizontal","vertical"]},"decorative":{"type":"boolean"}},"additionalProperties":false,"description":"Visual divider between content sections"},"HorizontalBarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["grouped","stacked"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"}},"required":["labels","series"],"additionalProperties":false,"description":"Horizontal bars; prefer when category labels are long or for ranked lists"},"Series":{"type":"object","properties":{"category":{"type":"string"},"values":{"type":"array","items":{"type":"number"}}},"required":["category","values"],"additionalProperties":false,"description":"One data series"},"RadarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}}},"required":["labels","series"],"additionalProperties":false,"description":"Spider/web chart; use for comparing multiple variables across one or more entities"},"PieChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}},"variant":{"type":"string","enum":["pie","donut"]},"appearance":{"type":"string","enum":["circular","semiCircular"]}},"required":["labels","values"],"additionalProperties":false,"description":"Circular slices; use plucked arrays: PieChart(data.categories, data.values)"},"RadialChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}}},"required":["labels","values"],"additionalProperties":false,"description":"Radial bars; use plucked arrays: RadialChart(data.categories, data.values)"},"SingleStackedBarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}}},"required":["labels","values"],"additionalProperties":false,"description":"Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)"},"ScatterChart":{"type":"object","properties":{"datasets":{"type":"array","items":{"$ref":"#/$defs/ScatterSeries"}},"xLabel":{"type":"string"},"yLabel":{"type":"string"}},"required":["datasets"],"additionalProperties":false,"description":"X/Y scatter plot; use for correlations, distributions, and clustering"},"ScatterSeries":{"type":"object","properties":{"name":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/$defs/Point"}}},"required":["name","points"],"additionalProperties":false,"description":"Named dataset"},"Point":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}},"required":["x","y"],"additionalProperties":false,"description":"Data point with numeric coordinates"},"AreaChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["linear","natural","step"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Filled area under lines; use for cumulative totals or volume trends over time"},"BarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["grouped","stacked"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Vertical bars; use for comparing values across categories with one or more series"},"LineChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["linear","natural","step"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Lines over categories; use for trends and continuous data over time"},"Table":{"type":"object","properties":{"columns":{"type":"array","items":{"$ref":"#/$defs/Col"}}},"required":["columns"],"additionalProperties":false,"description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"type":"object","properties":{"label":{"type":"string"},"data":{},"type":{"type":"string","enum":["string","number","action"]}},"required":["label","data"],"additionalProperties":false,"description":"Column definition — holds label + data array"},"TagBlock":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"}},"size":{"type":"string","enum":["sm","md","lg"]}},"required":["tags"],"additionalProperties":false,"description":"tags is an array of strings; optional size sm | md | lg"},"Form":{"type":"object","properties":{"name":{"type":"string"},"buttons":{"$ref":"#/$defs/Buttons"},"fields":{"default":[],"type":"array","items":{"$ref":"#/$defs/FormControl"}}},"required":["name","buttons","fields"],"additionalProperties":false,"description":"Form container with fields and explicit action buttons"},"Buttons":{"type":"object","properties":{"buttons":{"type":"array","items":{"$ref":"#/$defs/Button"}},"direction":{"type":"string","enum":["row","column"]}},"required":["buttons"],"additionalProperties":false,"description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"Button":{"type":"object","properties":{"label":{"type":"string"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"variant":{"type":"string","enum":["primary","secondary","tertiary"]},"type":{"type":"string","enum":["normal","destructive"]},"size":{"type":"string","enum":["extra-small","small","medium","large"]}},"required":["label"],"additionalProperties":false,"description":"Clickable button"},"FormControl":{"type":"object","properties":{"label":{"type":"string"},"input":{"anyOf":[{"$ref":"#/$defs/Input"},{"$ref":"#/$defs/TextArea"},{"$ref":"#/$defs/Select"},{"$ref":"#/$defs/DatePicker"},{"$ref":"#/$defs/Slider"},{"$ref":"#/$defs/CheckBoxGroup"},{"$ref":"#/$defs/RadioGroup"},{"$ref":"#/$defs/Chips"},{"$ref":"#/$defs/OptionCards"}]},"hint":{"type":"string"}},"required":["label","input"],"additionalProperties":false,"description":"Field with label, input component, and optional hint text"},"Input":{"type":"object","properties":{"name":{"type":"string"},"placeholder":{"type":"string"},"type":{"type":"string","enum":["text","email","password","number","url"]},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name"],"additionalProperties":false},"TextArea":{"type":"object","properties":{"name":{"type":"string"},"placeholder":{"type":"string"},"rows":{"type":"number"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name"],"additionalProperties":false},"Select":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/SelectItem"}},"placeholder":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"},"size":{"type":"string","enum":["small","medium","large"]}},"required":["name","items"],"additionalProperties":false},"SelectItem":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}},"required":["value","label"],"additionalProperties":false,"description":"Option for Select"},"DatePicker":{"type":"object","properties":{"name":{"type":"string"},"mode":{"type":"string","enum":["single","range"]},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{}},"required":["name"],"additionalProperties":false},"Slider":{"type":"object","properties":{"name":{"type":"string"},"variant":{"type":"string","enum":["continuous","discrete"]},"min":{"type":"number"},"max":{"type":"number"},"step":{"type":"number"},"defaultValue":{"type":"array","items":{"type":"number"}},"label":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"array","items":{"type":"number"}}},"required":["name","variant","min","max"],"additionalProperties":false,"description":"Numeric slider input; supports continuous and discrete (stepped) variants"},"CheckBoxGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/CheckBoxItem"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"boolean"}}},"required":["name","items"],"additionalProperties":false},"CheckBoxItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"},"defaultChecked":{"type":"boolean"}},"required":["label","description","name"],"additionalProperties":false},"RadioGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/RadioItem"}},"defaultValue":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name","items"],"additionalProperties":false},"RadioItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"value":{"type":"string"}},"required":["label","description","value"],"additionalProperties":false},"Chips":{"type":"object","properties":{"name":{"type":"string"},"type":{"default":"multiple","type":"string","enum":["single","multiple"]},"items":{"default":[],"type":"array","items":{"$ref":"#/$defs/ChipItem"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"defaultValue":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}},"required":["name","type","items"],"additionalProperties":false,"description":"A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`."},"ChipItem":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"disabled":{"type":"boolean"}},"required":["value","label"],"additionalProperties":false,"description":"A single selectable chip inside a Chips group, with a value, label and optional icon."},"Icon":{"type":"object","properties":{"name":{"type":"string"},"category":{"type":"string"}},"required":["name"],"additionalProperties":false,"description":"A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve."},"OptionCards":{"type":"object","properties":{"name":{"type":"string"},"type":{"default":"single","type":"string","enum":["single","multiple"]},"items":{"default":[],"type":"array","items":{"$ref":"#/$defs/OptionCard"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"defaultValue":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}},"required":["name","type","items"],"additionalProperties":false,"description":"A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`."},"OptionCard":{"type":"object","properties":{"value":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"topContent":{"anyOf":[{"$ref":"#/$defs/Icon"},{"$ref":"#/$defs/Image"}]},"disabled":{"type":"boolean"}},"required":["value","title"],"additionalProperties":false,"description":"A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top."},"IconButton":{"type":"object","properties":{"name":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"variant":{"type":"string","enum":["primary","secondary","tertiary"]},"size":{"type":"string","enum":["extra-small","small","medium","large"]},"shape":{"type":"string","enum":["square","circle"]}},"required":["name","icon"],"additionalProperties":false,"description":"Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click."},"Steps":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/StepsItem"}}},"required":["items"],"additionalProperties":false,"description":"Step-by-step guide"},"StepsItem":{"type":"object","properties":{"title":{"type":"string"},"details":{"type":"string"}},"required":["title","details"],"additionalProperties":false,"description":"title and details text for one step"},"InlineHeader":{"type":"object","properties":{"heading":{"type":"string"},"description":{"type":"string"}},"required":["heading"],"additionalProperties":false,"description":"Compact section heading with an optional one-line description, for use inside cards."},"EntityList":{"type":"object","properties":{"rows":{"default":[],"type":"array","items":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false}},"size":{"default":"default","type":"string","enum":["small","default"]},"header":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false},"footer":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false}},"required":["rows","size"],"additionalProperties":false,"description":"Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers."},"EditableTable":{"type":"object","properties":{"name":{"default":"","type":"string"},"columns":{"default":[],"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["text","number","date-single","select","url"]},"key":{"default":"default","type":"string"},"header":{"default":"","type":"string"},"width":{"type":"number"},"options":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}},"required":["value","label"],"additionalProperties":false}}},"required":["type","key","header"],"additionalProperties":false}},"data":{"default":[],"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"values":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}}},"required":["id","values"],"additionalProperties":false}}},"required":["name","columns","data"],"additionalProperties":false,"description":"Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field"},"SnippetCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/SnippetCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action."},"SnippetCardItem":{"type":"object","properties":{"id":{"type":"string"},"lhs":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"}]},"rhs":{"anyOf":[{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/BoldText"}]}},"required":["lhs"],"additionalProperties":false,"description":"One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)."},"IconText":{"type":"object","properties":{"icon":{"$ref":"#/$defs/Icon"},"iconVariant":{"default":"neutral","type":"string","enum":["neutral","info","success","warning","danger","inverted","filled","soft"]},"iconSize":{"default":"m","type":"string","enum":["xs","s","m","l","xl","sm","md","lg"]},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"},"layout":{"default":"horizontal","type":"string","enum":["horizontal","vertical"]}},"required":["icon","iconVariant","iconSize","title","bold","layout"],"additionalProperties":false,"description":"An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color."},"ImageText":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"},"layout":{"default":"horizontal","type":"string","enum":["horizontal","vertical"]},"imageSize":{"type":"number"}},"required":["src","title","bold","layout"],"additionalProperties":false,"description":"A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL."},"Text":{"type":"object","properties":{"variant":{"default":"text","type":"string","enum":["text","number"]},"value":{"type":"string"},"subtext":{"type":"string"},"subtextVariant":{"default":"text","type":"string","enum":["text","number","metric"]},"size":{"default":"sm","type":"string","enum":["xs","sm","md","lg"]}},"required":["variant","value","subtextVariant","size"],"additionalProperties":false,"description":"Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"BoldText":{"type":"object","properties":{"variant":{"default":"text","type":"string","enum":["text","number"]},"value":{"type":"string"},"subtext":{"type":"string"},"subtextVariant":{"default":"text","type":"string","enum":["text","number","metric"]},"size":{"default":"sm","type":"string","enum":["xs","sm","md","lg"]}},"required":["variant","value","subtextVariant","size"],"additionalProperties":false,"description":"Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"OverviewCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/OverviewCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action."},"OverviewCardItem":{"type":"object","properties":{"id":{"type":"string"},"top":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"},{"$ref":"#/$defs/Text"}]},"bottom":{"$ref":"#/$defs/MetricIndicatorInline"}},"required":["top"],"additionalProperties":false,"description":"One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom."},"MetricIndicatorInline":{"type":"object","properties":{"value":{"type":"string"},"subtext":{"type":"string"},"trend":{"type":"object","properties":{"direction":{"type":"string","enum":["up","down"]},"value":{"type":"number"}},"required":["direction","value"],"additionalProperties":false}},"required":["value"],"additionalProperties":false,"description":"Headline metric value with an optional +/- percentage trend and subtext, all on one line."},"ContextCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/ContextCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable."},"ContextCardItem":{"type":"object","properties":{"id":{"type":"string"},"title":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/Tag"}]},"body":{"type":"string"},"bgColor":{"type":"string","enum":["gray"]},"bgImageSrc":{"type":"string"},"bgImageAlt":{"type":"string"}},"required":["title"],"additionalProperties":false,"description":"A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image."},"Tag":{"type":"object","properties":{"text":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"size":{"type":"string","enum":["sm","md","lg"]},"variant":{"type":"string","enum":["neutral","info","success","warning","danger"]}},"required":["text"],"additionalProperties":false,"description":"Styled tag/badge with optional Icon and variant"},"CompositeCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/CompositeCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable."},"CompositeCardItem":{"type":"object","properties":{"id":{"type":"string"},"header":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"},{"$ref":"#/$defs/ImageTextLarge"},{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/Image"}]},"body":{"default":[],"type":"array","items":{"anyOf":[{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/BoldText"},{"$ref":"#/$defs/MetricIndicatorInline"},{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/ListBlock"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/EntityList"}]}},"footer":{"type":"object","properties":{"price":{"anyOf":[{"$ref":"#/$defs/BoldText"},{"$ref":"#/$defs/MetricIndicatorWithStrikethrough"}]},"button":{"$ref":"#/$defs/Button"}},"additionalProperties":false}},"required":["body"],"additionalProperties":false,"description":"A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer."},"ImageTextLarge":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"}},"required":["src","title","bold"],"additionalProperties":false,"description":"A full-width banner image above a bold title and optional subtitle. src must be a real image URL."},"ListBlock":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/ListItem"}},"variant":{"type":"string","enum":["number","image"]},"size":{"type":"string","enum":["default","small"]}},"required":["items"],"additionalProperties":false,"description":"A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list."},"ListItem":{"type":"object","properties":{"title":{"type":"string"},"subtitle":{"type":"string"},"image":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"}},"required":["src","alt"],"additionalProperties":false},"actionLabel":{"type":"string"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]}},"required":["title"],"additionalProperties":false,"description":"Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable."},"MetricIndicatorWithStrikethrough":{"type":"object","properties":{"value":{"type":"string"},"subtext":{"type":"string"},"previousValue":{"type":"string"},"trend":{"type":"object","properties":{"direction":{"type":"string","enum":["up","down"]},"value":{"type":"number"}},"required":["direction","value"],"additionalProperties":false}},"required":["value"],"additionalProperties":false,"description":"Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below."},"VisualCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/VisualCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable."},"VisualCardItem":{"type":"object","properties":{"body":{"$ref":"#/$defs/BoldText"},"id":{"type":"string"},"bgImageSrc":{"type":"string"},"tag":{"$ref":"#/$defs/Tag"},"bgImageAlt":{"type":"string"}},"required":["body"],"additionalProperties":false,"description":"A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)."},"Tabs":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/TabItem"}}},"required":["items"],"additionalProperties":false,"description":"Tabbed container"},"TabItem":{"type":"object","properties":{"value":{"type":"string"},"trigger":{"type":"string"},"content":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}}},"required":["value","trigger","content"],"additionalProperties":false,"description":"value is unique id, trigger is tab label, content is array of components"},"Carousel":{"type":"object","properties":{"children":{"type":"array","items":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}}},"variant":{"type":"string","enum":["card","sunk"]}},"required":["children"],"additionalProperties":false,"description":"Horizontal scrollable carousel"},"Stack":{"type":"object","properties":{"children":{"type":"array","items":{}},"direction":{"type":"string","enum":["row","column"]},"gap":{"type":"string","enum":["none","xs","s","m","l","xl","2xl"]},"align":{"type":"string","enum":["start","center","end","stretch","baseline"]},"justify":{"type":"string","enum":["start","center","end","between","around","evenly"]},"wrap":{"type":"boolean"}},"required":["children"],"additionalProperties":false,"description":"Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"."},"Slice":{"type":"object","properties":{"category":{"type":"string"},"value":{"type":"number"}},"required":["category","value"],"additionalProperties":false,"description":"One slice with label and numeric value"},"Label":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"],"additionalProperties":false,"description":"Text label"},"SwitchGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/SwitchItem"}},"variant":{"type":"string","enum":["clear","card","sunk"]},"value":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"boolean"}}},"required":["name","items"],"additionalProperties":false,"description":"Group of switch toggles"},"SwitchItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"},"defaultChecked":{"type":"boolean"}},"required":["name"],"additionalProperties":false,"description":"Individual switch toggle"},"Accordion":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/AccordionItem"}}},"required":["items"],"additionalProperties":false,"description":"Collapsible sections"},"AccordionItem":{"type":"object","properties":{"value":{"type":"string"},"trigger":{"type":"string"},"content":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}}},"required":["value","trigger","content"],"additionalProperties":false,"description":"value is unique id, trigger is section title"},"Modal":{"type":"object","properties":{"title":{"type":"string"},"open":{"type":"boolean"},"children":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}},"size":{"type":"string","enum":["sm","md","lg"]}},"required":["title","children"],"additionalProperties":false,"description":"Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children."}}},"examples":["Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]","Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])","Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])","Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]","Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")","Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])"],"additionalRules":["When asked about data, generate realistic/plausible data","For grid-like layouts, use Stack with direction \"row\" and wrap=true. Avoid justify=\"between\" unless you specifically want large gutters.","For forms, define one FormControl reference per field so controls can stream progressively.","For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).","Never nest Form inside Form.","Use @Reset($var1, $var2) after form submit to restore defaults — not @Set($var, \"\")","Multi-query refresh: Action([@Run(mutation), @Run(query1), @Run(query2), @Reset(...)])","$variables are reactive: changing via Select or @Set re-evaluates all Queries and expressions referencing them","Use existing components (Tabs, Accordion, Modal) before inventing ternary show/hide patterns","Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items; every item in a block must have the same structure.","Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicatorInline / MetricIndicatorWithStrikethrough are inline building blocks used INSIDE card items — do not place them directly in a Stack or Card.","EntityList size='small' (no header/footer) is only for use inside a CompositeCardItem body; use size='default' everywhere else.","Image URLs must be real (from a tool result or the user) — never invent or template an image URL.","Always pass a category to Icon — it enables a topical fallback when the exact icon name is unavailable.","EditableTable requires the consuming app to persist edits — use it only when the user or app explicitly asks for an editable table; default to Table for read-only data."]},"expected":"You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Stack(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Layout\nStack(children: any[], direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean) — Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\".\nTabs(items: TabItem[]) — Tabbed container\nTabItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[]) — value is unique id, trigger is tab label, content is array of components\nAccordion(items: AccordionItem[]) — Collapsible sections\nAccordionItem(value: string, trigger: string, content: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[]) — value is unique id, trigger is section title\nSteps(items: StepsItem[]) — Step-by-step guide\nStepsItem(title: string, details: string) — title and details text for one step\nCarousel(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[][], variant?: \"card\" | \"sunk\") — Horizontal scrollable carousel\nSeparator(orientation?: \"horizontal\" | \"vertical\", decorative?: boolean) — Visual divider between content sections\nModal(title: string, open?: $binding, children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock)[], size?: \"sm\" | \"md\" | \"lg\") — Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children.\n- For grid-like layouts, use Stack with direction \"row\" and wrap set to true.\n- Prefer justify \"start\" (or omit justify) with wrap=true for stable columns instead of uneven gutters.\n- Use nested Stacks when you need explicit rows/sections.\n- Show/hide sections: $editId != \"\" ? Card([editForm]) : null\n- Modal: Modal(\"Title\", $showModal, [content]) — $showModal is boolean, X/Escape auto-closes. Put Form with its own buttons inside children.\n- Use Tabs for alternative views (chart types, data sections) — no $variable needed\n- Shared filter across Tabs: same $days binding in Query args works across all TabItems\n\n### Content\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | Tabs | Carousel | Stack)[], variant?: \"card\" | \"sunk\" | \"clear\", direction?: \"row\" | \"column\", gap?: \"none\" | \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\", align?: \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\", justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\", wrap?: boolean) — Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts.\nCardHeader(title?: string, subtitle?: string) — Header with optional title and subtitle\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nMarkDownRenderer(textMarkdown: string, variant?: \"clear\" | \"card\" | \"sunk\") — Renders markdown text with optional container variant\nCallout(variant: \"info\" | \"warning\" | \"error\" | \"success\" | \"neutral\", title: string, description: string, visible?: $binding) — Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false.\nTextCallout(variant?: \"neutral\" | \"info\" | \"warning\" | \"success\" | \"danger\", title?: string, description?: string) — Text callout with variant, title, and description\nImage(alt: string, src?: string) — Image with alt text and optional URL\nImageBlock(src: string, alt?: string) — Image block with loading state\nImageGallery(images: {src: string, alt?: string, details?: string}[]) — Gallery grid of images with modal preview\nCodeBlock(language: string, codeString: string) — Syntax-highlighted code block\nInlineHeader(heading: string, description?: string) — Compact section heading with an optional one-line description, for use inside cards.\n- InlineHeader is a compact heading + description pair for labelling a block (lighter than CardHeader).\n- Use Cards to group related KPIs or sections. Stack with direction \"row\" for side-by-side layouts.\n- Success toast: Callout(\"success\", \"Saved\", \"Done.\", $showSuccess) — use @Set($showSuccess, true) in save action, auto-dismisses after 3s. For errors: result.status == \"error\" ? Callout(\"error\", \"Failed\", result.error) : null\n- KPI card: Card([TextContent(\"Label\", \"small\"), TextContent(\"\" + @Count(@Filter(data.rows, \"field\", \"==\", \"value\")), \"large-heavy\")])\n\n### Tables\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\nEditableTable(name?: string, columns?: {type: \"text\" | \"number\" | \"date-single\" | \"select\" | \"url\", key?: string, header?: string, width?: number, options?: {value: string, label: string}[]}[], data?: {id: string, values: (string | number)[]}[]) — Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field\n- EditableTable lets the user edit cells inline. Give it a unique name, columns of { type, key, header } with type one of text | number | date-single | select | url (select also needs options: [{ value, label }]).\n- data is an array of { id, values } rows where values are ordered positionally to match columns. Edited data is submitted when the user clicks Save Changes.\n- Table is COLUMN-oriented: Table([Col(\"Label\", dataArray), Col(\"Count\", countArray, \"number\")]). Use array pluck for data: data.rows.fieldName\n- Col data can be component arrays for styled cells: Col(\"Status\", @Each(data.rows, \"item\", Tag(item.status, null, \"sm\", item.status == \"open\" ? \"success\" : \"danger\")))\n- Row actions: Col(\"Actions\", @Each(data.rows, \"t\", Button(\"Edit\", Action([@Set($showEdit, true), @Set($editId, t.id)]))))\n- Sortable: sorted = @Sort(data.rows, $sortField, \"desc\"). Bind $sortField to Select. Use sorted.fieldName for Col data\n- Searchable: filtered = @Filter(data.rows, \"title\", \"contains\", $search). Bind $search to Input\n- Chain sort + filter: filtered = @Filter(...) then sorted = @Sort(filtered, ...) — use sorted for both Table and Charts\n- Empty state: @Count(data.rows) > 0 ? Table([...]) : TextContent(\"No data yet\")\n\n### Charts (2D)\nBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string, height?: number) — Vertical bars; use for comparing values across categories with one or more series\nLineChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Lines over categories; use for trends and continuous data over time\nAreaChart(labels: string[], series: Series[], variant?: \"linear\" | \"natural\" | \"step\", xLabel?: string, yLabel?: string, height?: number) — Filled area under lines; use for cumulative totals or volume trends over time\nRadarChart(labels: string[], series: Series[]) — Spider/web chart; use for comparing multiple variables across one or more entities\nHorizontalBarChart(labels: string[], series: Series[], variant?: \"grouped\" | \"stacked\", xLabel?: string, yLabel?: string) — Horizontal bars; prefer when category labels are long or for ranked lists\nSeries(category: string, values: number[]) — One data series\n- Charts accept column arrays: LineChart(labels, [Series(\"Name\", values)]). Use array pluck: LineChart(data.rows.day, [Series(\"Views\", data.rows.views)])\n- Use Cards to wrap charts with CardHeader for titled sections\n- Chart + Table from same source: use @Sort or @Filter result for both LineChart and Table Col data\n- Multiple chart views: use Tabs — Tabs([TabItem(\"line\", \"Line\", [LineChart(...)]), TabItem(\"bar\", \"Bar\", [BarChart(...)])])\n\n### Charts (1D)\nPieChart(labels: string[], values: number[], variant?: \"pie\" | \"donut\", appearance?: \"circular\" | \"semiCircular\") — Circular slices; use plucked arrays: PieChart(data.categories, data.values)\nRadialChart(labels: string[], values: number[]) — Radial bars; use plucked arrays: RadialChart(data.categories, data.values)\nSingleStackedBarChart(labels: string[], values: number[]) — Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)\nSlice(category: string, value: number) — One slice with label and numeric value\n- PieChart and BarChart need NUMBERS, not objects. For list data, use @Count(@Filter(...)) to aggregate:\n- PieChart from list: `PieChart([\"Low\", \"Med\", \"High\"], [@Count(@Filter(data.rows, \"priority\", \"==\", \"low\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"medium\")), @Count(@Filter(data.rows, \"priority\", \"==\", \"high\"))], \"donut\")`\n- KPI from count: `TextContent(\"\" + @Count(@Filter(data.rows, \"status\", \"==\", \"open\")), \"large-heavy\")`\n\n### Charts (Scatter)\nScatterChart(datasets: ScatterSeries[], xLabel?: string, yLabel?: string) — X/Y scatter plot; use for correlations, distributions, and clustering\nScatterSeries(name: string, points: Point[]) — Named dataset\nPoint(x: number, y: number, z?: number) — Data point with numeric coordinates\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nLabel(text: string) — Text label\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nTextArea(name: string, placeholder?: string, rows?: number, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nDatePicker(name: string, mode?: \"single\" | \"range\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSlider(name: string, variant: \"continuous\" | \"discrete\", min: number, max: number, step?: number, defaultValue?: number[], label?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding) — Numeric slider input; supports continuous and discrete (stepped) variants\nCheckBoxGroup(name: string, items: CheckBoxItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding>)\nCheckBoxItem(label: string, description: string, name: string, defaultChecked?: boolean)\nRadioGroup(name: string, items: RadioItem[], defaultValue?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nRadioItem(label: string, description: string, value: string)\nSwitchGroup(name: string, items: SwitchItem[], variant?: \"clear\" | \"card\" | \"sunk\", value?: $binding>) — Group of switch toggles\nSwitchItem(label?: string, description?: string, name: string, defaultChecked?: boolean) — Individual switch toggle\nChips(name: string, type?: \"single\" | \"multiple\", items?: ChipItem[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`.\nChipItem(value: string, label: string, icon?: Icon, disabled?: boolean) — A single selectable chip inside a Chips group, with a value, label and optional icon.\nOptionCards(name: string, type?: \"single\" | \"multiple\", items?: OptionCard[], rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, defaultValue?: string | string[]) — A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`.\nOptionCard(value: string, title: string, subtitle?: string, topContent?: Icon | Image, disabled?: boolean) — A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top.\n- Chips: compact single/multiple selection pills. Use ChipItem references for each option.\n- OptionCards: larger selectable cards with title, subtitle and an optional Icon or Image on top. Use OptionCard references for each option.\n- For Form fields, define EACH FormControl as its own reference — do NOT inline all controls in one array. This allows progressive field-by-field streaming.\n- NEVER nest Form inside Form — each Form should be a standalone container.\n- Form requires explicit buttons. Always pass a Buttons(...) reference as the third Form argument.\n- rules is an optional object: {required: true, email: true, minLength: 8, maxLength: 100}\n- Available rules: required, email, min, max, minLength, maxLength, pattern, url, numeric\n- The renderer shows error messages automatically — do NOT generate error text in the UI\n- Conditional fields: $country == \"US\" ? stateField : $country == \"UK\" ? postcodeField : addressField\n- Edit form in Modal: Modal(\"Edit\", $showEdit, [Form(\"edit\", Buttons([saveBtn, cancelBtn]), [fields...])]). Save button should include @Set($showEdit, false) to close modal.\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nIconButton(name: string, icon: Icon, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\", shape?: \"square\" | \"circle\") — Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click.\n- Icon renders a lucide icon by kebab-case name; it is also used as the icon of IconButton, IconText and OptionCard.\n- Toggle in @Each: @Each(rows, \"t\", Button(t.status == \"open\" ? \"Close\" : \"Reopen\", Action([...])))\n\n### Data Display\nTagBlock(tags: string[], size?: \"sm\" | \"md\" | \"lg\") — tags is an array of strings; optional size sm | md | lg\nTag(text: string, icon?: Icon, size?: \"sm\" | \"md\" | \"lg\", variant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\") — Styled tag/badge with optional Icon and variant\nIcon(name: string, category?: string) — A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve.\nEntityList(rows?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}[], size?: \"small\" | \"default\", header?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}, footer?: {left: string, right: string, rightVariant?: \"text\" | \"number\"}) — Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers.\nListBlock(items: ListItem[], variant?: \"number\" | \"image\", size?: \"default\" | \"small\") — A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list.\nListItem(title: string, subtitle?: string, image?: {src: string, alt: string}, actionLabel?: string, action?: ActionExpression) — Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable.\n- Color-mapped Tag: Tag(value, null, \"sm\", value == \"high\" ? \"danger\" : value == \"medium\" ? \"warning\" : \"neutral\")\n- EntityList is a compact two-column list of { left, right } rows (e.g. name / value). size='default' also supports a header and footer row; size='small' does not.\n- ListBlock is a numbered or image list of ListItem references. An action on ListItem is optional.\n\n### Cards\nSnippetCardBlock(items: SnippetCardItem[], layout?: \"grid\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action.\nSnippetCardItem(id?: string, lhs: IconText | ImageText, rhs?: Text | BoldText) — One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText).\nOverviewCardBlock(items: OverviewCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action.\nOverviewCardItem(id?: string, top: IconText | ImageText | Text, bottom?: MetricIndicatorInline) — One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom.\nContextCardBlock(items: ContextCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable.\nContextCardItem(id?: string, title: string | Tag, body?: string, bgColor?: \"gray\", bgImageSrc?: string, bgImageAlt?: string) — A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image.\nCompositeCardBlock(items: CompositeCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable.\nCompositeCardItem(id?: string, header?: IconText | ImageText | ImageTextLarge | Text | Image, body?: (Text | BoldText | MetricIndicatorInline | IconText | Image | AreaChart | BarChart | LineChart | ListBlock | TagBlock | EntityList)[], footer?: {price?: BoldText | MetricIndicatorWithStrikethrough, button?: Button}) — A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer.\nVisualCardBlock(items: VisualCardItem[], layout?: \"grid\" | \"carousel\", responsive?: boolean, action?: ActionExpression, gap?: number | string) — A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable.\nVisualCardItem(body: BoldText, id?: string, bgImageSrc?: string, tag?: Tag, bgImageAlt?: string) — A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text).\nText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nBoldText(variant?: \"text\" | \"number\", value: string, subtext?: string, subtextVariant?: \"text\" | \"number\" | \"metric\", size?: \"xs\" | \"sm\" | \"md\" | \"lg\") — Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red.\nIconText(icon: Icon, iconVariant?: \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\" | \"inverted\" | \"filled\" | \"soft\", iconSize?: \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"sm\" | \"md\" | \"lg\", title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\") — An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color.\nImageText(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean, layout?: \"horizontal\" | \"vertical\", imageSize?: number) — A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL.\nImageTextLarge(src: string, alt?: string, title: string, subtitle?: string, bold?: boolean) — A full-width banner image above a bold title and optional subtitle. src must be a real image URL.\nMetricIndicatorInline(value: string, subtext?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional +/- percentage trend and subtext, all on one line.\nMetricIndicatorWithStrikethrough(value: string, subtext?: string, previousValue?: string, trend?: {direction: \"up\" | \"down\", value: number}) — Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below.\n- Card blocks lay out 2+ items in a responsive grid (or carousel where supported). Every item in a block must have the same structure.\n- SnippetCardItem: small card with lhs (IconText | ImageText) and optional rhs (Text | BoldText) — good for key/value facts.\n- OverviewCardItem: small card with top (IconText | ImageText | Text) and optional bottom MetricIndicatorInline — good for KPIs.\n- ContextCardItem: medium card with a title (string or Tag), body text and optional background image — good for summaries.\n- CompositeCardItem: rich card with header, body array (Text, BoldText, MetricIndicatorInline, IconText, Image, charts, ListBlock, TagBlock, EntityList) and footer (price + Button) — good for products/offers.\n- VisualCardItem: image-first card with a BoldText body and optional Tag.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicator* are the inline building blocks used INSIDE card items; do not place them directly in the root Card.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Stack(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Stack(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n\n## Examples\n\nExample 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]\n\nExample 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])\n\nExample 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])\n\nExample 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]\n\nExample 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")\n\nExample 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])\n\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Stack(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n\n- When asked about data, generate realistic/plausible data\n- For grid-like layouts, use Stack with direction \"row\" and wrap=true. Avoid justify=\"between\" unless you specifically want large gutters.\n- For forms, define one FormControl reference per field so controls can stream progressively.\n- For forms, always provide the second Form argument with Buttons(...) actions: Form(name, buttons, fields).\n- Never nest Form inside Form.\n- Use @Reset($var1, $var2) after form submit to restore defaults — not @Set($var, \"\")\n- Multi-query refresh: Action([@Run(mutation), @Run(query1), @Run(query2), @Reset(...)])\n- $variables are reactive: changing via Select or @Set re-evaluates all Queries and expressions referencing them\n- Use existing components (Tabs, Accordion, Modal) before inventing ternary show/hide patterns\n- Card blocks (SnippetCardBlock, OverviewCardBlock, ContextCardBlock, CompositeCardBlock, VisualCardBlock) need at least 2 items; every item in a block must have the same structure.\n- Text / BoldText / IconText / ImageText / ImageTextLarge / MetricIndicatorInline / MetricIndicatorWithStrikethrough are inline building blocks used INSIDE card items — do not place them directly in a Stack or Card.\n- EntityList size='small' (no header/footer) is only for use inside a CompositeCardItem body; use size='default' everywhere else.\n- Image URLs must be real (from a tool result or the user) — never invent or template an image URL.\n- Always pass a category to Icon — it enables a topical fallback when the exact icon name is unavailable.\n- EditableTable requires the consuming app to persist edits — use it only when the user or app explicitly asks for an editable table; default to Table for read-only data."}, +{"name":"slice-bindings","spec":{"root":"Card","components":{"Card":{"signature":"Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])","description":"Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent."},"TextContent":{"signature":"TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")","description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"Button":{"signature":"Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")","description":"Clickable button"},"Buttons":{"signature":"Buttons(buttons: Button[], direction?: \"row\" | \"column\")","description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"Form":{"signature":"Form(name: string, buttons: Buttons, fields?: FormControl[])","description":"Form container with fields and explicit action buttons"},"FormControl":{"signature":"FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)","description":"Field with label, input component, and optional hint text"},"Input":{"signature":"Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Select":{"signature":"Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")","description":""},"SelectItem":{"signature":"SelectItem(value: string, label: string)","description":"Option for Select"},"Table":{"signature":"Table(columns: Col[])","description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"signature":"Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")","description":"Column definition — holds label + data array"}},"componentGroups":[{"name":"Forms","components":["Form","FormControl","Input","Select","SelectItem"],"notes":["- Forms note"]},{"name":"Buttons","components":["Button","Buttons","Missing"]}],"bindings":true},"expected":"You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n8. Declare mutable state with `$varName = defaultValue`. Components marked with `$binding` can read/write these. Undeclared $variables are auto-created with null default.\n9. String concatenation: `\"text\" + $var + \"more\"`\n10. Dot member access: `query.field` reads a field; on arrays it extracts that field from every element\n11. Index access: `arr[0]`, `data[index]`\n12. Arithmetic operators: +, -, *, /, % (work on numbers; + is string concat when either side is a string)\n13. Comparison: ==, !=, >, <, >=, <=\n14. Logical: &&, ||, ! (prefix)\n15. Ternary: `condition ? valueIfTrue : valueIfFalse`\n16. Parentheses for grouping: `(a + b) * c`\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl, @Set, @Reset).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\n- Forms note\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Built-in Functions\n\nData functions prefixed with `@` to distinguish from components. These are the ONLY functions available — do NOT invent new ones.\nUse @-prefixed built-in functions (@Count, @Sum, @Avg, @Min, @Max, @Round) on Query results — do NOT hardcode computed values.\n\n@Count(array) → number — Returns array length\n@First(array) → element — Returns first element of array\n@Last(array) → element — Returns last element of array\n@Sum(numbers[]) → number — Sum of numeric array\n@Avg(numbers[]) → number — Average of numeric array\n@Min(numbers[]) → number — Minimum value in array\n@Max(numbers[]) → number — Maximum value in array\n@Sort(array, field, direction?) → sorted array — Sort array by field. Direction: \"asc\" (default) or \"desc\"\n@Filter(array, field, operator: \"==\" | \"!=\" | \">\" | \"<\" | \">=\" | \"<=\" | \"contains\", value) → filtered array — Filter array by field value\n@Round(number, decimals?) → number — Round to N decimal places (default 0)\n@Abs(number) → number — Absolute value\n@Floor(number) → number — Round down to nearest integer\n@Ceil(number) → number — Round up to nearest integer\n@Each(array, varName, template) — Evaluate template for each element. varName is the loop variable — use it ONLY inside the template expression (inline). Do NOT create a separate statement for the template.\n\nBuiltins compose — output of one is input to the next:\n`@Count(@Filter(data.rows, \"field\", \"==\", \"val\"))` for KPIs/chart values, `@Round(@Avg(data.rows.score), 1)`, `@Each(data.rows, \"item\", Comp(item.field))` for per-item rendering.\nArray pluck: `data.rows.field` extracts a field from every row → use with @Sum, @Avg, charts, tables.\n\nIMPORTANT @Each rule: The loop variable (e.g. \"item\") is ONLY available inside the @Each template expression. Always inline the template — do NOT extract it to a separate statement.\nCORRECT: `Col(\"Actions\", @Each(rows, \"t\", Button(\"Edit\", Action([@Set($id, t.id)]))))`\nWRONG: `myBtn = Button(\"Edit\", Action([@Set($id, t.id)]))` then `Col(\"Actions\", @Each(rows, \"t\", myBtn))` — t is undefined in myBtn.\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n- @Set($variable, value) — Set a $variable to a specific value\n- @Reset($var1, $var2, ...) — Reset $variables to their declared defaults (e.g. @Reset($title, $priority) restores $title=\"\" and $priority=\"medium\")\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. $variable declarations — state ready for bindings\n3. Query statements — defaults resolve immediately so components render with data\n4. Component definitions — fill in with data already available\n5. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n3. Every $binding appears in at least one component or expression."}, +{"name":"slice-tools","spec":{"root":"Card","components":{"Card":{"signature":"Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])","description":"Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent."},"TextContent":{"signature":"TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")","description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"Button":{"signature":"Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")","description":"Clickable button"},"Buttons":{"signature":"Buttons(buttons: Button[], direction?: \"row\" | \"column\")","description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"Form":{"signature":"Form(name: string, buttons: Buttons, fields?: FormControl[])","description":"Form container with fields and explicit action buttons"},"FormControl":{"signature":"FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)","description":"Field with label, input component, and optional hint text"},"Input":{"signature":"Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Select":{"signature":"Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")","description":""},"SelectItem":{"signature":"SelectItem(value: string, label: string)","description":"Option for Select"},"Table":{"signature":"Table(columns: Col[])","description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"signature":"Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")","description":"Column definition — holds label + data array"}},"componentGroups":[{"name":"Forms","components":["Form","FormControl","Input","Select","SelectItem"],"notes":["- Forms note"]},{"name":"Buttons","components":["Button","Buttons","Missing"]}],"tools":["search_docs",{"name":"list_tickets","description":"Open support tickets","inputSchema":{"type":"object","properties":{"status":{"type":"string","enum":["open","closed"]},"limit":{"type":"number"}},"required":["status"]},"outputSchema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"}}}},"total":{"type":"integer"}}}},{"name":"ping","inputSchema":{}}],"toolExamples":["x = Query(\"list_tickets\", {status: \"open\"}, {rows: []})"]},"expected":"You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n8. Declare mutable state with `$varName = defaultValue`. Components marked with `$binding` can read/write these. Undeclared $variables are auto-created with null default.\n9. String concatenation: `\"text\" + $var + \"more\"`\n10. Dot member access: `query.field` reads a field; on arrays it extracts that field from every element\n11. Index access: `arr[0]`, `data[index]`\n12. Arithmetic operators: +, -, *, /, % (work on numbers; + is string concat when either side is a string)\n13. Comparison: ==, !=, >, <, >=, <=\n14. Logical: &&, ||, ! (prefix)\n15. Ternary: `condition ? valueIfTrue : valueIfFalse`\n16. Parentheses for grouping: `(a + b) * c`\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@Run, @ToAssistant, @OpenUrl, @Set, @Reset).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\n- Forms note\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Built-in Functions\n\nData functions prefixed with `@` to distinguish from components. These are the ONLY functions available — do NOT invent new ones.\nUse @-prefixed built-in functions (@Count, @Sum, @Avg, @Min, @Max, @Round) on Query results — do NOT hardcode computed values.\n\n@Count(array) → number — Returns array length\n@First(array) → element — Returns first element of array\n@Last(array) → element — Returns last element of array\n@Sum(numbers[]) → number — Sum of numeric array\n@Avg(numbers[]) → number — Average of numeric array\n@Min(numbers[]) → number — Minimum value in array\n@Max(numbers[]) → number — Maximum value in array\n@Sort(array, field, direction?) → sorted array — Sort array by field. Direction: \"asc\" (default) or \"desc\"\n@Filter(array, field, operator: \"==\" | \"!=\" | \">\" | \"<\" | \">=\" | \"<=\" | \"contains\", value) → filtered array — Filter array by field value\n@Round(number, decimals?) → number — Round to N decimal places (default 0)\n@Abs(number) → number — Absolute value\n@Floor(number) → number — Round down to nearest integer\n@Ceil(number) → number — Round up to nearest integer\n@Each(array, varName, template) — Evaluate template for each element. varName is the loop variable — use it ONLY inside the template expression (inline). Do NOT create a separate statement for the template.\n\nBuiltins compose — output of one is input to the next:\n`@Count(@Filter(data.rows, \"field\", \"==\", \"val\"))` for KPIs/chart values, `@Round(@Avg(data.rows.score), 1)`, `@Each(data.rows, \"item\", Comp(item.field))` for per-item rendering.\nArray pluck: `data.rows.field` extracts a field from every row → use with @Sum, @Avg, charts, tables.\n\nIMPORTANT @Each rule: The loop variable (e.g. \"item\") is ONLY available inside the @Each template expression. Always inline the template — do NOT extract it to a separate statement.\nCORRECT: `Col(\"Actions\", @Each(rows, \"t\", Button(\"Edit\", Action([@Set($id, t.id)]))))`\nWRONG: `myBtn = Button(\"Edit\", Action([@Set($id, t.id)]))` then `Col(\"Actions\", @Each(rows, \"t\", myBtn))` — t is undefined in myBtn.\n\n## Query — Live Data Fetching\n\nFetch data from available tools. Returns defaults instantly, swaps in real data when it arrives.\n\n```\nmetrics = Query(\"tool_name\", {arg1: value, arg2: $binding}, {defaultField: 0, defaultData: []}, refreshInterval?)\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (may reference $bindings — re-fetches automatically on change)\n- Third arg: default data (rendered immediately before fetch resolves)\n- Fourth arg (optional): refresh interval in seconds (e.g. 30 for auto-refresh every 30s)\n- Use dot access on results: metrics.totalEvents, metrics.data.day (array pluck)\n- Query results must use regular identifiers: `metrics = Query(...)`, NOT `$metrics = Query(...)`\n- Manual refresh: `Button(\"Refresh\", Action([@Run(query1), @Run(query2)]), \"secondary\")` — re-fetches the listed queries\n- Refresh all queries: create Action with @Run for each query\n\n## Mutation — Write Operations\n\nExecute state-changing tool calls (create, update, delete). Unlike Query (auto-fetches on render), Mutation fires only on button click via Action.\n\n```\nresult = Mutation(\"tool_name\", {arg1: $binding, arg2: \"value\"})\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (evaluated with current $binding values at click time)\n- result.status: \"idle\" | \"loading\" | \"success\" | \"error\"\n- result.data: tool response on success\n- result.error: error message on failure\n- Mutation results use regular identifiers: `result = Mutation(...)`, NOT `$result`\n- Show loading state: `result.status == \"loading\" ? TextContent(\"Saving...\") : null`\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @Run(queryOrMutationRef) — Execute a Mutation or re-fetch a Query (ref must be a declared Query/Mutation)\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n- @Set($variable, value) — Set a $variable to a specific value\n- @Reset($var1, $var2, ...) — Reset $variables to their declared defaults (e.g. @Reset($title, $priority) restores $title=\"\" and $priority=\"medium\")\n\nExample — mutation + refresh + reset (PREFERRED pattern):\n```\n$binding = \"default\"\nresult = Mutation(\"tool_name\", {field: $binding})\ndata = Query(\"tool_name\", {}, {rows: []})\nonSubmit = Action([@Run(result), @Run(data), @Reset($binding)])\n```\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n- If a @Run(mutation) step fails, remaining steps are skipped (halt on failure)\n- @Run(queryRef) re-fetches the query (fire-and-forget, cannot fail)\n\n## Interactive Filters\n\nTo let the user filter data with a dropdown:\n1. Declare a $variable with a default: `$dateRange = \"14\"`\n2. Create a Select with name, items, and binding: `Select(\"dateRange\", [SelectItem(\"7\", \"Last 7 days\"), ...], null, null, $dateRange)`\n3. Wrap in FormControl for a label: `FormControl(\"Date Range\", Select(...))`\n4. Pass $dateRange in Query args: `Query(\"tool\", {dateRange: $dateRange}, {defaults})`\n5. When the user changes the Select, $dateRange updates and the Query automatically re-fetches\n\nFILTER WIRING RULE: If a $binding filter is visible in the UI, EVERY relevant Query MUST reference that $binding in its args. Never show a filter dropdown while hardcoding the query args.\n\nRules for $variables:\n- $variables hold simple values (strings or numbers), NOT arrays or objects\n- $variables must be bound to a Select/Input component via the value argument (last positional arg) to be interactive\n- Queries must use regular identifiers (NOT $variables): `metrics = Query(...)` not `$metrics = Query(...)`\n- **Auto-declare**: You do NOT need to explicitly declare $variables. If you use `$foo` without declaring it, the parser auto-creates `$foo = null`. You can still declare explicitly to set a default: `$days = \"14\"`\n\n## Forms\n\nSimple form — no $bindings needed. Field values are managed internally by the Form via the name prop:\n```\ncontactForm = Form(\"contact\", submitBtn, [nameField, emailField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", {required: true}))\nemailField = FormControl(\"Email\", Input(\"email\", \"your@email.com\", \"email\", {required: true, email: true}))\nsubmitBtn = Button(\"Submit\")\n```\n\nUse $bindings when you need to read field values elsewhere (in Action context, Query args, or conditionals). They are auto-declared:\n```\n$role = \"engineer\"\ncontactForm = Form(\"contact\", submitBtn, [nameField, emailField, roleField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Enter your name\", \"text\", {required: true}, $name))\nemailField = FormControl(\"Email\", Input(\"email\", \"Enter your email\", \"email\", {required: true, email: true}, $email))\nroleField = FormControl(\"Role\", Select(\"role\", [SelectItem(\"engineer\", \"Engineer\"), SelectItem(\"designer\", \"Designer\"), SelectItem(\"pm\", \"PM\")], null, {required: true}, $role))\nsubmitBtn = Button(\"Submit\")\n```\n\nFor form + mutation patterns (create, refresh, reset), see the Action section example above.\n\nIMPORTANT: Always add validation rules to form fields used with Mutations. Use OBJECT syntax: {required: true, email: true, minLength: 8}. The renderer shows error messages automatically and blocks submit when validation fails.\n\n## Data Workflow\n\nWhen tools are available, follow this workflow:\n1. FIRST: Call the most relevant tool to inspect the real data shape before generating code\n2. Use Query() for READ operations (data that should stay live) — NEVER hardcode tool results as literal arrays or objects\n3. Use Mutation() for WRITE operations (create, update, delete) — triggered by button clicks via Action([@Run(mutationRef)])\n4. Use the real data from step 1 as condensed Query defaults (3-5 rows) so the UI renders immediately\n5. Use @-prefixed builtins (@Count, @Filter, @Sort, @Sum) on Query results for KPIs and aggregations — the runtime evaluates these live on every refresh\n6. Hardcoded arrays are ONLY for static display data (labels, options) where no tool exists\n\nWRONG — you called a tool and got data back, but you inlined the results:\n```\nopenCount = 2\nitem1 = SomeComp(\"first item title\")\nitem2 = SomeComp(\"second item title\")\nlist = SomeList([item1, item2])\nchart = SomeChart([\"A\", \"B\"], [12, 8])\n```\nThis is static — it shows stale data and won't update. Creating item1, item2, item3... manually is ALWAYS wrong when a tool exists.\n\nRIGHT — use Query() for live data, Mutation() for writes, @builtins to derive values:\n```\ndata = Query(\"tool_name\", {}, {rows: []})\nopenCount = @Count(@Filter(data.rows, \"field\", \"==\", \"value\"))\nlist = @Each(data.rows, \"item\", SomeComp(item.title, item.field))\ncreateResult = Mutation(\"create_tool\", {title: $title})\nsubmitBtn = Button(\"Create\", Action([@Run(createResult), @Run(data), @Reset($title)]))\n```\nEverything derives from the Query — when data refreshes, the entire dashboard updates automatically.\n\n## Available Tools\n\nUse these with Query() for read operations or Mutation() for write operations. The LLM decides which is appropriate based on the tool's purpose.\n\n- search_docs\n- list_tickets(status: \"open\" | \"closed\", limit?: number) → {rows?: {id?: string}[], total?: number}\n Open support tickets\n- ping()\n\n### Default values for Query results\n\nUse these shapes as minimal Query defaults:\n- list_tickets: `{\"rows\":[],\"total\":0}`\n\nCRITICAL: Use ONLY the tools listed above in Query() and Mutation() calls. Do NOT invent or guess tool names. If the user asks for functionality that doesn't match any available tool, use realistic mock data instead of fabricating a tool call.\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. $variable declarations — state ready for bindings\n3. Query statements — defaults resolve immediately so components render with data\n4. Component definitions — fill in with data already available\n5. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n\n## Examples\n\nx = Query(\"list_tickets\", {status: \"open\"}, {rows: []})\n\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n3. Every Query result is referenced by at least one component.\n4. Every $binding appears in at least one component or expression.\n5. Every visible filter $binding appears in at least one Query args object."}, +{"name":"slice-tools-no-bindings","spec":{"root":"Card","components":{"Card":{"signature":"Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])","description":"Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent."},"TextContent":{"signature":"TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")","description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"Button":{"signature":"Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")","description":"Clickable button"},"Buttons":{"signature":"Buttons(buttons: Button[], direction?: \"row\" | \"column\")","description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"Form":{"signature":"Form(name: string, buttons: Buttons, fields?: FormControl[])","description":"Form container with fields and explicit action buttons"},"FormControl":{"signature":"FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)","description":"Field with label, input component, and optional hint text"},"Input":{"signature":"Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Select":{"signature":"Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")","description":""},"SelectItem":{"signature":"SelectItem(value: string, label: string)","description":"Option for Select"},"Table":{"signature":"Table(columns: Col[])","description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"signature":"Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")","description":"Column definition — holds label + data array"}},"componentGroups":[{"name":"Forms","components":["Form","FormControl","Input","Select","SelectItem"],"notes":["- Forms note"]},{"name":"Buttons","components":["Button","Buttons","Missing"]}],"tools":["search_docs",{"name":"list_tickets","description":"Open support tickets","inputSchema":{"type":"object","properties":{"status":{"type":"string","enum":["open","closed"]},"limit":{"type":"number"}},"required":["status"]},"outputSchema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"}}}},"total":{"type":"integer"}}}},{"name":"ping","inputSchema":{}}],"bindings":false},"expected":"You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n8. String concatenation: `\"text\" + $var + \"more\"`\n9. Dot member access: `query.field` reads a field; on arrays it extracts that field from every element\n10. Index access: `arr[0]`, `data[index]`\n11. Arithmetic operators: +, -, *, /, % (work on numbers; + is string concat when either side is a string)\n12. Comparison: ==, !=, >, <, >=, <=\n13. Logical: &&, ||, ! (prefix)\n14. Ternary: `condition ? valueIfTrue : valueIfFalse`\n15. Parentheses for grouping: `(a + b) * c`\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@Run, @ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\n- Forms note\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Built-in Functions\n\nData functions prefixed with `@` to distinguish from components. These are the ONLY functions available — do NOT invent new ones.\nUse @-prefixed built-in functions (@Count, @Sum, @Avg, @Min, @Max, @Round) on Query results — do NOT hardcode computed values.\n\n@Count(array) → number — Returns array length\n@First(array) → element — Returns first element of array\n@Last(array) → element — Returns last element of array\n@Sum(numbers[]) → number — Sum of numeric array\n@Avg(numbers[]) → number — Average of numeric array\n@Min(numbers[]) → number — Minimum value in array\n@Max(numbers[]) → number — Maximum value in array\n@Sort(array, field, direction?) → sorted array — Sort array by field. Direction: \"asc\" (default) or \"desc\"\n@Filter(array, field, operator: \"==\" | \"!=\" | \">\" | \"<\" | \">=\" | \"<=\" | \"contains\", value) → filtered array — Filter array by field value\n@Round(number, decimals?) → number — Round to N decimal places (default 0)\n@Abs(number) → number — Absolute value\n@Floor(number) → number — Round down to nearest integer\n@Ceil(number) → number — Round up to nearest integer\n@Each(array, varName, template) — Evaluate template for each element. varName is the loop variable — use it ONLY inside the template expression (inline). Do NOT create a separate statement for the template.\n\nBuiltins compose — output of one is input to the next:\n`@Count(@Filter(data.rows, \"field\", \"==\", \"val\"))` for KPIs/chart values, `@Round(@Avg(data.rows.score), 1)`, `@Each(data.rows, \"item\", Comp(item.field))` for per-item rendering.\nArray pluck: `data.rows.field` extracts a field from every row → use with @Sum, @Avg, charts, tables.\n\nIMPORTANT @Each rule: The loop variable (e.g. \"item\") is ONLY available inside the @Each template expression. Always inline the template — do NOT extract it to a separate statement.\nCORRECT: `Col(\"Actions\", @Each(rows, \"t\", Button(\"Edit\", Action([@Set($id, t.id)]))))`\nWRONG: `myBtn = Button(\"Edit\", Action([@Set($id, t.id)]))` then `Col(\"Actions\", @Each(rows, \"t\", myBtn))` — t is undefined in myBtn.\n\n## Query — Live Data Fetching\n\nFetch data from available tools. Returns defaults instantly, swaps in real data when it arrives.\n\n```\nmetrics = Query(\"tool_name\", {arg1: value, arg2: $binding}, {defaultField: 0, defaultData: []}, refreshInterval?)\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (may reference $bindings — re-fetches automatically on change)\n- Third arg: default data (rendered immediately before fetch resolves)\n- Fourth arg (optional): refresh interval in seconds (e.g. 30 for auto-refresh every 30s)\n- Use dot access on results: metrics.totalEvents, metrics.data.day (array pluck)\n- Query results must use regular identifiers: `metrics = Query(...)`, NOT `$metrics = Query(...)`\n- Manual refresh: `Button(\"Refresh\", Action([@Run(query1), @Run(query2)]), \"secondary\")` — re-fetches the listed queries\n- Refresh all queries: create Action with @Run for each query\n\n## Mutation — Write Operations\n\nExecute state-changing tool calls (create, update, delete). Unlike Query (auto-fetches on render), Mutation fires only on button click via Action.\n\n```\nresult = Mutation(\"tool_name\", {arg1: $binding, arg2: \"value\"})\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (evaluated with current $binding values at click time)\n- result.status: \"idle\" | \"loading\" | \"success\" | \"error\"\n- result.data: tool response on success\n- result.error: error message on failure\n- Mutation results use regular identifiers: `result = Mutation(...)`, NOT `$result`\n- Show loading state: `result.status == \"loading\" ? TextContent(\"Saving...\") : null`\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @Run(queryOrMutationRef) — Execute a Mutation or re-fetch a Query (ref must be a declared Query/Mutation)\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — mutation + refresh + reset (PREFERRED pattern):\n```\n$binding = \"default\"\nresult = Mutation(\"tool_name\", {field: $binding})\ndata = Query(\"tool_name\", {}, {rows: []})\nonSubmit = Action([@Run(result), @Run(data), @Reset($binding)])\n```\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n- If a @Run(mutation) step fails, remaining steps are skipped (halt on failure)\n- @Run(queryRef) re-fetches the query (fire-and-forget, cannot fail)\n\n## Data Workflow\n\nWhen tools are available, follow this workflow:\n1. FIRST: Call the most relevant tool to inspect the real data shape before generating code\n2. Use Query() for READ operations (data that should stay live) — NEVER hardcode tool results as literal arrays or objects\n3. Use Mutation() for WRITE operations (create, update, delete) — triggered by button clicks via Action([@Run(mutationRef)])\n4. Use the real data from step 1 as condensed Query defaults (3-5 rows) so the UI renders immediately\n5. Use @-prefixed builtins (@Count, @Filter, @Sort, @Sum) on Query results for KPIs and aggregations — the runtime evaluates these live on every refresh\n6. Hardcoded arrays are ONLY for static display data (labels, options) where no tool exists\n\nWRONG — you called a tool and got data back, but you inlined the results:\n```\nopenCount = 2\nitem1 = SomeComp(\"first item title\")\nitem2 = SomeComp(\"second item title\")\nlist = SomeList([item1, item2])\nchart = SomeChart([\"A\", \"B\"], [12, 8])\n```\nThis is static — it shows stale data and won't update. Creating item1, item2, item3... manually is ALWAYS wrong when a tool exists.\n\nRIGHT — use Query() for live data, Mutation() for writes, @builtins to derive values:\n```\ndata = Query(\"tool_name\", {}, {rows: []})\nopenCount = @Count(@Filter(data.rows, \"field\", \"==\", \"value\"))\nlist = @Each(data.rows, \"item\", SomeComp(item.title, item.field))\ncreateResult = Mutation(\"create_tool\", {title: $title})\nsubmitBtn = Button(\"Create\", Action([@Run(createResult), @Run(data), @Reset($title)]))\n```\nEverything derives from the Query — when data refreshes, the entire dashboard updates automatically.\n\n## Available Tools\n\nUse these with Query() for read operations or Mutation() for write operations. The LLM decides which is appropriate based on the tool's purpose.\n\n- search_docs\n- list_tickets(status: \"open\" | \"closed\", limit?: number) → {rows?: {id?: string}[], total?: number}\n Open support tickets\n- ping()\n\n### Default values for Query results\n\nUse these shapes as minimal Query defaults:\n- list_tickets: `{\"rows\":[],\"total\":0}`\n\nCRITICAL: Use ONLY the tools listed above in Query() and Mutation() calls. Do NOT invent or guess tool names. If the user asks for functionality that doesn't match any available tool, use realistic mock data instead of fabricating a tool call.\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. $variable declarations — state ready for bindings\n3. Query statements — defaults resolve immediately so components render with data\n4. Component definitions — fill in with data already available\n5. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n3. Every Query result is referenced by at least one component."}, +{"name":"slice-modes","spec":{"root":"Card","components":{"Card":{"signature":"Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])","description":"Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent."},"TextContent":{"signature":"TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")","description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"Button":{"signature":"Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")","description":"Clickable button"},"Buttons":{"signature":"Buttons(buttons: Button[], direction?: \"row\" | \"column\")","description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"Form":{"signature":"Form(name: string, buttons: Buttons, fields?: FormControl[])","description":"Form container with fields and explicit action buttons"},"FormControl":{"signature":"FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)","description":"Field with label, input component, and optional hint text"},"Input":{"signature":"Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Select":{"signature":"Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")","description":""},"SelectItem":{"signature":"SelectItem(value: string, label: string)","description":"Option for Select"},"Table":{"signature":"Table(columns: Col[])","description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"signature":"Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")","description":"Column definition — holds label + data array"}},"componentGroups":[{"name":"Forms","components":["Form","FormControl","Input","Select","SelectItem"],"notes":["- Forms note"]},{"name":"Buttons","components":["Button","Buttons","Missing"]}],"editMode":true,"inlineMode":true,"preamble":"Custom preamble.","additionalRules":["Be brief"],"examples":["a = 1"]},"expected":"Custom preamble.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\n### Forms\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\n- Forms note\n\n### Buttons\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\n\n### Other\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n\n## Examples\n\na = 1\n\n\n## Edit Mode\n\nThe runtime merges by statement name: same name = replace, new name = append.\nOutput ONLY statements that changed or are new. Everything else is kept automatically.\n\n### Delete\nTo remove a component, re-declare its parent without that component in the parent's children array. The removed component and any statements only it referenced are automatically garbage-collected.\n\n### Patch size guide\n- Changing a title or label: 1 statement\n- Adding a component: 2-3 statements (the new component + parent update)\n- Removing a component: 1 statement (re-declare parent without the removed child)\n- Adding a filter + wiring to query: 3-5 statements\n- Restructuring into tabs: 5-10 statements\n\n### Rules\n- Reuse existing statement names exactly — do not rename\n- Do NOT re-emit unchanged statements — the runtime keeps them\n- A typical edit patch is 1-10 statements, not 20+\n- If the existing code already satisfies the request, output only the root statement\n- NEVER output the entire program as a patch. Only output what actually changes\n- If you are about to output more than 10 statements, reconsider — most edits need fewer\n\n## Inline Mode\n\nYou are in inline mode. You can respond in two ways:\n\n### 1. Code response (when the user wants to CREATE or CHANGE the UI)\nWrap openui-lang code in triple-backtick fences. You can include explanatory text before/after:\n\nHere's your dashboard:\n\n```openui-lang\nroot = RootComp([header, content])\nheader = SomeHeader(\"Title\")\ncontent = SomeContent(\"Hello world\")\n```\n\nI created a simple layout with a header.\n\n### 2. Text-only response (when the user asks a QUESTION)\nIf the user asks \"what is this?\", \"explain the chart\", \"how does this work\", etc. — respond with plain text. Do NOT output any openui-lang code. The existing dashboard stays unchanged.\n\n### Rules\n- When the user asks for changes, output ONLY the changed/new statements in a fenced block\n- When the user asks a question, respond with text only — NO code. The dashboard stays unchanged.\n- The parser extracts code from fences automatically. Text outside fences is shown as chat.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n\n- Be brief"}, +{"name":"slice-no-groups","spec":{"root":"Card","components":{"Card":{"signature":"Card(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[])","description":"Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent."},"TextContent":{"signature":"TextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\")","description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"Button":{"signature":"Button(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\")","description":"Clickable button"},"Buttons":{"signature":"Buttons(buttons: Button[], direction?: \"row\" | \"column\")","description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"Form":{"signature":"Form(name: string, buttons: Buttons, fields?: FormControl[])","description":"Form container with fields and explicit action buttons"},"FormControl":{"signature":"FormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string)","description":"Field with label, input component, and optional hint text"},"Input":{"signature":"Input(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)","description":""},"Select":{"signature":"Select(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")","description":""},"SelectItem":{"signature":"SelectItem(value: string, label: string)","description":"Option for Select"},"Table":{"signature":"Table(columns: Col[])","description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"signature":"Col(label: string, data: any, type?: \"string\" | \"number\" | \"action\")","description":"Column definition — holds label + data array"}}},"expected":"You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Card(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\nProps typed `ActionExpression` accept an Action([@steps...]) expression. See the Action section for available steps (@ToAssistant, @OpenUrl).\nProps marked `$binding` accept a `$variable` reference for two-way binding.\n\nCard(children: (TextContent | MarkDownRenderer | CardHeader | Callout | TextCallout | CodeBlock | Image | ImageBlock | ImageGallery | Separator | HorizontalBarChart | RadarChart | PieChart | RadialChart | SingleStackedBarChart | ScatterChart | AreaChart | BarChart | LineChart | Table | TagBlock | Form | Buttons | IconButton | Steps | InlineHeader | EntityList | EditableTable | SnippetCardBlock | OverviewCardBlock | ContextCardBlock | CompositeCardBlock | VisualCardBlock | ListBlock | FollowUpBlock | SectionBlock | Tabs | Carousel)[], sources?: {url?: string, title: string, sourceName: string}[]) — Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent.\nTextContent(text: string, size?: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\") — Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\".\nButton(label: string, action?: ActionExpression, variant?: \"primary\" | \"secondary\" | \"tertiary\", type?: \"normal\" | \"destructive\", size?: \"extra-small\" | \"small\" | \"medium\" | \"large\") — Clickable button\nButtons(buttons: Button[], direction?: \"row\" | \"column\") — Group of Button components. direction: \"row\" (default) | \"column\".\nForm(name: string, buttons: Buttons, fields?: FormControl[]) — Form container with fields and explicit action buttons\nFormControl(label: string, input: Input | TextArea | Select | DatePicker | Slider | CheckBoxGroup | RadioGroup | Chips | OptionCards, hint?: string) — Field with label, input component, and optional hint text\nInput(name: string, placeholder?: string, type?: \"text\" | \"email\" | \"password\" | \"number\" | \"url\", rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding)\nSelect(name: string, items: SelectItem[], placeholder?: string, rules?: {required?: boolean, email?: boolean, url?: boolean, numeric?: boolean, min?: number, max?: number, minLength?: number, maxLength?: number, pattern?: string}, value?: $binding, size?: \"small\" | \"medium\" | \"large\")\nSelectItem(value: string, label: string) — Option for Select\nTable(columns: Col[]) — Data table — column-oriented. Each Col holds its own data array.\nCol(label: string, data: any, type?: \"string\" | \"number\" | \"action\") — Column definition — holds label + data array\n\n## Action — Button Behavior\n\nAction([@steps...]) wires button clicks to operations. Steps are @-prefixed built-in actions. Steps execute in order.\nButtons without an explicit Action prop automatically send their label to the assistant (equivalent to Action([@ToAssistant(label)])).\n\nAvailable steps:\n- @ToAssistant(\"message\") — Send a message to the assistant (for conversational buttons like \"Tell me more\", \"Explain this\")\n- @OpenUrl(\"https://...\") — Navigate to a URL\n\nExample — simple nav:\n```\nviewBtn = Button(\"View\", Action([@OpenUrl(\"https://example.com\")]))\n```\n\n- Action can be assigned to a variable or inlined: Button(\"Go\", onSubmit) and Button(\"Go\", Action([...])) both work\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Card(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Card(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Card(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root."}, +{"name":"small-no-root","spec":{"components":{"Box":{"signature":"Box(children: (Text | Box)[])","description":"A box"},"Text":{"signature":"Text(value: string, tone?: \"a\" | \"b\")"}}},"expected":"You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Root(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\n\nBox(children: (Text | Box)[]) — A box\nText(value: string, tone?: \"a\" | \"b\")\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Root(...)` — UI shell appears immediately\n2. Component definitions — fill in as they stream\n3. Data values — leaf content last\n\nAlways write the root = Root(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Root(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root."}, +{"name":"small-tools-only","spec":{"components":{"Box":{"signature":"Box(children: (Text | Box)[])","description":"A box"},"Text":{"signature":"Text(value: string, tone?: \"a\" | \"b\")"}},"toolCalls":true,"bindings":false},"expected":"You are an AI assistant that responds using openui-lang, a declarative UI language. Your ENTIRE response must be valid openui-lang code — no markdown, no explanations, just openui-lang.\n\n## Syntax Rules\n\n1. Each statement is on its own line: `identifier = Expression`\n2. `root` is the entry point — every program must define `root = Root(...)`\n3. Expressions are: strings (\"...\"), numbers, booleans (true/false), null, arrays ([...]), objects ({...}), or component calls TypeName(arg1, arg2, ...)\n4. Use references for readability: define `name = ...` on one line, then use `name` later\n5. EVERY variable (except root) MUST be referenced by at least one other variable. Unreferenced variables are silently dropped and will NOT render. Always include defined variables in their parent's children/items array.\n6. Arguments are POSITIONAL (order matters, not names). Write `SomeComp([children], \"row\", \"l\")` NOT `SomeComp([children], direction: \"row\", gap: \"l\")` — colon syntax is NOT supported and silently breaks\n7. Optional arguments can be omitted from the end\n8. String concatenation: `\"text\" + $var + \"more\"`\n9. Dot member access: `query.field` reads a field; on arrays it extracts that field from every element\n10. Index access: `arr[0]`, `data[index]`\n11. Arithmetic operators: +, -, *, /, % (work on numbers; + is string concat when either side is a string)\n12. Comparison: ==, !=, >, <, >=, <=\n13. Logical: &&, ||, ! (prefix)\n14. Ternary: `condition ? valueIfTrue : valueIfFalse`\n15. Parentheses for grouping: `(a + b) * c`\n- Strings use double quotes with backslash escaping\n\n## Component Signatures\n\nArguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.\n\nBox(children: (Text | Box)[]) — A box\nText(value: string, tone?: \"a\" | \"b\")\n\n## Built-in Functions\n\nData functions prefixed with `@` to distinguish from components. These are the ONLY functions available — do NOT invent new ones.\nUse @-prefixed built-in functions (@Count, @Sum, @Avg, @Min, @Max, @Round) on Query results — do NOT hardcode computed values.\n\n@Count(array) → number — Returns array length\n@First(array) → element — Returns first element of array\n@Last(array) → element — Returns last element of array\n@Sum(numbers[]) → number — Sum of numeric array\n@Avg(numbers[]) → number — Average of numeric array\n@Min(numbers[]) → number — Minimum value in array\n@Max(numbers[]) → number — Maximum value in array\n@Sort(array, field, direction?) → sorted array — Sort array by field. Direction: \"asc\" (default) or \"desc\"\n@Filter(array, field, operator: \"==\" | \"!=\" | \">\" | \"<\" | \">=\" | \"<=\" | \"contains\", value) → filtered array — Filter array by field value\n@Round(number, decimals?) → number — Round to N decimal places (default 0)\n@Abs(number) → number — Absolute value\n@Floor(number) → number — Round down to nearest integer\n@Ceil(number) → number — Round up to nearest integer\n@Each(array, varName, template) — Evaluate template for each element. varName is the loop variable — use it ONLY inside the template expression (inline). Do NOT create a separate statement for the template.\n\nBuiltins compose — output of one is input to the next:\n`@Count(@Filter(data.rows, \"field\", \"==\", \"val\"))` for KPIs/chart values, `@Round(@Avg(data.rows.score), 1)`, `@Each(data.rows, \"item\", Comp(item.field))` for per-item rendering.\nArray pluck: `data.rows.field` extracts a field from every row → use with @Sum, @Avg, charts, tables.\n\nIMPORTANT @Each rule: The loop variable (e.g. \"item\") is ONLY available inside the @Each template expression. Always inline the template — do NOT extract it to a separate statement.\nCORRECT: `Col(\"Actions\", @Each(rows, \"t\", Button(\"Edit\", Action([@Set($id, t.id)]))))`\nWRONG: `myBtn = Button(\"Edit\", Action([@Set($id, t.id)]))` then `Col(\"Actions\", @Each(rows, \"t\", myBtn))` — t is undefined in myBtn.\n\n## Query — Live Data Fetching\n\nFetch data from available tools. Returns defaults instantly, swaps in real data when it arrives.\n\n```\nmetrics = Query(\"tool_name\", {arg1: value, arg2: $binding}, {defaultField: 0, defaultData: []}, refreshInterval?)\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (may reference $bindings — re-fetches automatically on change)\n- Third arg: default data (rendered immediately before fetch resolves)\n- Fourth arg (optional): refresh interval in seconds (e.g. 30 for auto-refresh every 30s)\n- Use dot access on results: metrics.totalEvents, metrics.data.day (array pluck)\n- Query results must use regular identifiers: `metrics = Query(...)`, NOT `$metrics = Query(...)`\n- Manual refresh: `Button(\"Refresh\", Action([@Run(query1), @Run(query2)]), \"secondary\")` — re-fetches the listed queries\n- Refresh all queries: create Action with @Run for each query\n\n## Mutation — Write Operations\n\nExecute state-changing tool calls (create, update, delete). Unlike Query (auto-fetches on render), Mutation fires only on button click via Action.\n\n```\nresult = Mutation(\"tool_name\", {arg1: $binding, arg2: \"value\"})\n```\n\n- First arg: tool name (string)\n- Second arg: arguments object (evaluated with current $binding values at click time)\n- result.status: \"idle\" | \"loading\" | \"success\" | \"error\"\n- result.data: tool response on success\n- result.error: error message on failure\n- Mutation results use regular identifiers: `result = Mutation(...)`, NOT `$result`\n- Show loading state: `result.status == \"loading\" ? TextContent(\"Saving...\") : null`\n\n## Data Workflow\n\nWhen tools are available, follow this workflow:\n1. FIRST: Call the most relevant tool to inspect the real data shape before generating code\n2. Use Query() for READ operations (data that should stay live) — NEVER hardcode tool results as literal arrays or objects\n3. Use Mutation() for WRITE operations (create, update, delete) — triggered by button clicks via Action([@Run(mutationRef)])\n4. Use the real data from step 1 as condensed Query defaults (3-5 rows) so the UI renders immediately\n5. Use @-prefixed builtins (@Count, @Filter, @Sort, @Sum) on Query results for KPIs and aggregations — the runtime evaluates these live on every refresh\n6. Hardcoded arrays are ONLY for static display data (labels, options) where no tool exists\n\nWRONG — you called a tool and got data back, but you inlined the results:\n```\nopenCount = 2\nitem1 = SomeComp(\"first item title\")\nitem2 = SomeComp(\"second item title\")\nlist = SomeList([item1, item2])\nchart = SomeChart([\"A\", \"B\"], [12, 8])\n```\nThis is static — it shows stale data and won't update. Creating item1, item2, item3... manually is ALWAYS wrong when a tool exists.\n\nRIGHT — use Query() for live data, Mutation() for writes, @builtins to derive values:\n```\ndata = Query(\"tool_name\", {}, {rows: []})\nopenCount = @Count(@Filter(data.rows, \"field\", \"==\", \"value\"))\nlist = @Each(data.rows, \"item\", SomeComp(item.title, item.field))\ncreateResult = Mutation(\"create_tool\", {title: $title})\nsubmitBtn = Button(\"Create\", Action([@Run(createResult), @Run(data), @Reset($title)]))\n```\nEverything derives from the Query — when data refreshes, the entire dashboard updates automatically.\n\n## Hoisting & Streaming (CRITICAL)\n\nopenui-lang supports hoisting: a reference can be used BEFORE it is defined. The parser resolves all references after the full input is parsed.\n\nDuring streaming, the output is re-parsed on every chunk. Undefined references are temporarily unresolved and appear once their definitions stream in. This creates a progressive top-down reveal — structure first, then data fills in.\n\n**Recommended statement order for optimal streaming:**\n1. `root = Root(...)` — UI shell appears immediately\n2. $variable declarations — state ready for bindings\n3. Query statements — defaults resolve immediately so components render with data\n4. Component definitions — fill in with data already available\n5. Data values — leaf content last\n\nAlways write the root = Root(...) statement first so the UI shell appears immediately, even before child data has streamed in.\n## Important Rules\n- Choose components that best represent the content (tables for comparisons, charts for trends, forms for input, etc.)\n\n## Final Verification\nBefore finishing, walk your output and verify:\n1. root = Root(...) is the FIRST line (for optimal streaming).\n2. Every referenced name is defined. Every defined name (other than root) is reachable from root.\n3. Every Query result is referenced by at least one component."} ] diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json index 1edd8a7193..6f9dbe227f 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/schemas.json @@ -1,8679 +1,6 @@ { - "chat": { - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "Card": { - "$ref": "#/$defs/Card" - }, - "CardHeader": { - "$ref": "#/$defs/CardHeader" - }, - "TextContent": { - "$ref": "#/$defs/TextContent" - }, - "MarkDownRenderer": { - "$ref": "#/$defs/MarkDownRenderer" - }, - "Callout": { - "$ref": "#/$defs/Callout" - }, - "TextCallout": { - "$ref": "#/$defs/TextCallout" - }, - "Image": { - "$ref": "#/$defs/Image" - }, - "ImageBlock": { - "$ref": "#/$defs/ImageBlock" - }, - "ImageGallery": { - "$ref": "#/$defs/ImageGallery" - }, - "CodeBlock": { - "$ref": "#/$defs/CodeBlock" - }, - "Separator": { - "$ref": "#/$defs/Separator" - }, - "Table": { - "$ref": "#/$defs/Table" - }, - "Col": { - "$ref": "#/$defs/Col" - }, - "BarChart": { - "$ref": "#/$defs/BarChart" - }, - "LineChart": { - "$ref": "#/$defs/LineChart" - }, - "AreaChart": { - "$ref": "#/$defs/AreaChart" - }, - "RadarChart": { - "$ref": "#/$defs/RadarChart" - }, - "HorizontalBarChart": { - "$ref": "#/$defs/HorizontalBarChart" - }, - "Series": { - "$ref": "#/$defs/Series" - }, - "PieChart": { - "$ref": "#/$defs/PieChart" - }, - "RadialChart": { - "$ref": "#/$defs/RadialChart" - }, - "SingleStackedBarChart": { - "$ref": "#/$defs/SingleStackedBarChart" - }, - "Slice": { - "$ref": "#/$defs/Slice" - }, - "ScatterChart": { - "$ref": "#/$defs/ScatterChart" - }, - "ScatterSeries": { - "$ref": "#/$defs/ScatterSeries" - }, - "Point": { - "$ref": "#/$defs/Point" - }, - "Form": { - "$ref": "#/$defs/Form" - }, - "FormControl": { - "$ref": "#/$defs/FormControl" - }, - "Label": { - "$ref": "#/$defs/Label" - }, - "Input": { - "$ref": "#/$defs/Input" - }, - "TextArea": { - "$ref": "#/$defs/TextArea" - }, - "Select": { - "$ref": "#/$defs/Select" - }, - "SelectItem": { - "$ref": "#/$defs/SelectItem" - }, - "DatePicker": { - "$ref": "#/$defs/DatePicker" - }, - "Slider": { - "$ref": "#/$defs/Slider" - }, - "CheckBoxGroup": { - "$ref": "#/$defs/CheckBoxGroup" - }, - "CheckBoxItem": { - "$ref": "#/$defs/CheckBoxItem" - }, - "RadioGroup": { - "$ref": "#/$defs/RadioGroup" - }, - "RadioItem": { - "$ref": "#/$defs/RadioItem" - }, - "SwitchGroup": { - "$ref": "#/$defs/SwitchGroup" - }, - "SwitchItem": { - "$ref": "#/$defs/SwitchItem" - }, - "Button": { - "$ref": "#/$defs/Button" - }, - "Buttons": { - "$ref": "#/$defs/Buttons" - }, - "ListBlock": { - "$ref": "#/$defs/ListBlock" - }, - "ListItem": { - "$ref": "#/$defs/ListItem" - }, - "FollowUpBlock": { - "$ref": "#/$defs/FollowUpBlock" - }, - "FollowUpItem": { - "$ref": "#/$defs/FollowUpItem" - }, - "SectionBlock": { - "$ref": "#/$defs/SectionBlock" - }, - "SectionItem": { - "$ref": "#/$defs/SectionItem" - }, - "Tabs": { - "$ref": "#/$defs/Tabs" - }, - "TabItem": { - "$ref": "#/$defs/TabItem" - }, - "Accordion": { - "$ref": "#/$defs/Accordion" - }, - "AccordionItem": { - "$ref": "#/$defs/AccordionItem" - }, - "Steps": { - "$ref": "#/$defs/Steps" - }, - "StepsItem": { - "$ref": "#/$defs/StepsItem" - }, - "Carousel": { - "$ref": "#/$defs/Carousel" - }, - "TagBlock": { - "$ref": "#/$defs/TagBlock" - }, - "Tag": { - "$ref": "#/$defs/Tag" - }, - "EntityList": { - "$ref": "#/$defs/EntityList" - }, - "InlineHeader": { - "$ref": "#/$defs/InlineHeader" - }, - "Icon": { - "$ref": "#/$defs/Icon" - }, - "IconButton": { - "$ref": "#/$defs/IconButton" - }, - "EditableTable": { - "$ref": "#/$defs/EditableTable" - }, - "ChipItem": { - "$ref": "#/$defs/ChipItem" - }, - "Chips": { - "$ref": "#/$defs/Chips" - }, - "OptionCard": { - "$ref": "#/$defs/OptionCard" - }, - "OptionCards": { - "$ref": "#/$defs/OptionCards" - }, - "Text": { - "$ref": "#/$defs/Text" - }, - "BoldText": { - "$ref": "#/$defs/BoldText" - }, - "IconText": { - "$ref": "#/$defs/IconText" - }, - "ImageText": { - "$ref": "#/$defs/ImageText" - }, - "ImageTextLarge": { - "$ref": "#/$defs/ImageTextLarge" - }, - "MetricIndicatorInline": { - "$ref": "#/$defs/MetricIndicatorInline" - }, - "MetricIndicatorWithStrikethrough": { - "$ref": "#/$defs/MetricIndicatorWithStrikethrough" - }, - "SnippetCardItem": { - "$ref": "#/$defs/SnippetCardItem" - }, - "SnippetCardBlock": { - "$ref": "#/$defs/SnippetCardBlock" - }, - "OverviewCardItem": { - "$ref": "#/$defs/OverviewCardItem" - }, - "OverviewCardBlock": { - "$ref": "#/$defs/OverviewCardBlock" - }, - "ContextCardItem": { - "$ref": "#/$defs/ContextCardItem" - }, - "ContextCardBlock": { - "$ref": "#/$defs/ContextCardBlock" - }, - "CompositeCardItem": { - "$ref": "#/$defs/CompositeCardItem" - }, - "CompositeCardBlock": { - "$ref": "#/$defs/CompositeCardBlock" - }, - "VisualCardItem": { - "$ref": "#/$defs/VisualCardItem" - }, - "VisualCardBlock": { - "$ref": "#/$defs/VisualCardBlock" - } - }, - "required": [ - "Card", - "CardHeader", - "TextContent", - "MarkDownRenderer", - "Callout", - "TextCallout", - "Image", - "ImageBlock", - "ImageGallery", - "CodeBlock", - "Separator", - "Table", - "Col", - "BarChart", - "LineChart", - "AreaChart", - "RadarChart", - "HorizontalBarChart", - "Series", - "PieChart", - "RadialChart", - "SingleStackedBarChart", - "Slice", - "ScatterChart", - "ScatterSeries", - "Point", - "Form", - "FormControl", - "Label", - "Input", - "TextArea", - "Select", - "SelectItem", - "DatePicker", - "Slider", - "CheckBoxGroup", - "CheckBoxItem", - "RadioGroup", - "RadioItem", - "SwitchGroup", - "SwitchItem", - "Button", - "Buttons", - "ListBlock", - "ListItem", - "FollowUpBlock", - "FollowUpItem", - "SectionBlock", - "SectionItem", - "Tabs", - "TabItem", - "Accordion", - "AccordionItem", - "Steps", - "StepsItem", - "Carousel", - "TagBlock", - "Tag", - "EntityList", - "InlineHeader", - "Icon", - "IconButton", - "EditableTable", - "ChipItem", - "Chips", - "OptionCard", - "OptionCards", - "Text", - "BoldText", - "IconText", - "ImageText", - "ImageTextLarge", - "MetricIndicatorInline", - "MetricIndicatorWithStrikethrough", - "SnippetCardItem", - "SnippetCardBlock", - "OverviewCardItem", - "OverviewCardBlock", - "ContextCardItem", - "ContextCardBlock", - "CompositeCardItem", - "CompositeCardBlock", - "VisualCardItem", - "VisualCardBlock" - ], - "additionalProperties": false, - "$defs": { - "Card": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - }, - { - "$ref": "#/$defs/ListBlock" - }, - { - "$ref": "#/$defs/FollowUpBlock" - }, - { - "$ref": "#/$defs/SectionBlock" - }, - { - "$ref": "#/$defs/Tabs" - }, - { - "$ref": "#/$defs/Carousel" - } - ] - } - }, - "sources": { - "type": "array", - "items": { - "type": "object", - "properties": { - "url": { - "type": "string" - }, - "title": { - "type": "string" - }, - "sourceName": { - "type": "string" - } - }, - "required": [ - "title", - "sourceName" - ], - "additionalProperties": false - } - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent." - }, - "TextContent": { - "type": "object", - "properties": { - "text": { - "type": "string" - }, - "size": { - "type": "string", - "enum": [ - "small", - "default", - "large", - "small-heavy", - "large-heavy" - ] - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "MarkDownRenderer": { - "type": "object", - "properties": { - "textMarkdown": { - "type": "string" - }, - "variant": { - "type": "string", - "enum": [ - "clear", - "card", - "sunk" - ] - } - }, - "required": [ - "textMarkdown" - ], - "additionalProperties": false, - "description": "Renders markdown text with optional container variant" - }, - "CardHeader": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - } - }, - "additionalProperties": false, - "description": "Header with optional title and subtitle" - }, - "Callout": { - "type": "object", - "properties": { - "variant": { - "type": "string", - "enum": [ - "info", - "warning", - "error", - "success", - "neutral" - ] - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "visible": { - "type": "boolean" - } - }, - "required": [ - "variant", - "title", - "description" - ], - "additionalProperties": false, - "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." - }, - "TextCallout": { - "type": "object", - "properties": { - "variant": { - "type": "string", - "enum": [ - "neutral", - "info", - "warning", - "success", - "danger" - ] - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - } - }, - "additionalProperties": false, - "description": "Text callout with variant, title, and description" - }, - "CodeBlock": { - "type": "object", - "properties": { - "language": { - "type": "string" - }, - "codeString": { - "type": "string" - } - }, - "required": [ - "language", - "codeString" - ], - "additionalProperties": false, - "description": "Syntax-highlighted code block" - }, - "Image": { - "type": "object", - "properties": { - "alt": { - "type": "string" - }, - "src": { - "type": "string" - } - }, - "required": [ - "alt" - ], - "additionalProperties": false, - "description": "Image with alt text and optional URL" - }, - "ImageBlock": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - } - }, - "required": [ - "src" - ], - "additionalProperties": false, - "description": "Image block with loading state" - }, - "ImageGallery": { - "type": "object", - "properties": { - "images": { - "type": "array", - "items": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "details": { - "type": "string" - } - }, - "required": [ - "src" - ], - "additionalProperties": false - } - } - }, - "required": [ - "images" - ], - "additionalProperties": false, - "description": "Gallery grid of images with modal preview" - }, - "Separator": { - "type": "object", - "properties": { - "orientation": { - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - }, - "decorative": { - "type": "boolean" - } - }, - "additionalProperties": false, - "description": "Visual divider between content sections" - }, - "HorizontalBarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "grouped", - "stacked" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Horizontal bars; prefer when category labels are long or for ranked lists" - }, - "Series": { - "type": "object", - "properties": { - "category": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "category", - "values" - ], - "additionalProperties": false, - "description": "One data series" - }, - "RadarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Spider/web chart; use for comparing multiple variables across one or more entities" - }, - "PieChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - }, - "variant": { - "type": "string", - "enum": [ - "pie", - "donut" - ] - }, - "appearance": { - "type": "string", - "enum": [ - "circular", - "semiCircular" - ] - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" - }, - "RadialChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" - }, - "SingleStackedBarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" - }, - "ScatterChart": { - "type": "object", - "properties": { - "datasets": { - "type": "array", - "items": { - "$ref": "#/$defs/ScatterSeries" - } - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - } - }, - "required": [ - "datasets" - ], - "additionalProperties": false, - "description": "X/Y scatter plot; use for correlations, distributions, and clustering" - }, - "ScatterSeries": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "points": { - "type": "array", - "items": { - "$ref": "#/$defs/Point" - } - } - }, - "required": [ - "name", - "points" - ], - "additionalProperties": false, - "description": "Named dataset" - }, - "Point": { - "type": "object", - "properties": { - "x": { - "type": "number" - }, - "y": { - "type": "number" - }, - "z": { - "type": "number" - } - }, - "required": [ - "x", - "y" - ], - "additionalProperties": false, - "description": "Data point with numeric coordinates" - }, - "AreaChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "linear", - "natural", - "step" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Filled area under lines; use for cumulative totals or volume trends over time" - }, - "BarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "grouped", - "stacked" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Vertical bars; use for comparing values across categories with one or more series" - }, - "LineChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "linear", - "natural", - "step" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Lines over categories; use for trends and continuous data over time" - }, - "Table": { - "type": "object", - "properties": { - "columns": { - "type": "array", - "items": { - "$ref": "#/$defs/Col" - } - } - }, - "required": [ - "columns" - ], - "additionalProperties": false, - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "data": {}, - "type": { - "type": "string", - "enum": [ - "string", - "number", - "action" - ] - } - }, - "required": [ - "label", - "data" - ], - "additionalProperties": false, - "description": "Column definition — holds label + data array" - }, - "TagBlock": { - "type": "object", - "properties": { - "tags": { - "type": "array", - "items": { - "type": "string" - } - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "tags" - ], - "additionalProperties": false, - "description": "tags is an array of strings; optional size sm | md | lg" - }, - "Form": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "buttons": { - "$ref": "#/$defs/Buttons" - }, - "fields": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/FormControl" - } - } - }, - "required": [ - "name", - "buttons", - "fields" - ], - "additionalProperties": false, - "description": "Form container with fields and explicit action buttons" - }, - "Buttons": { - "type": "object", - "properties": { - "buttons": { - "type": "array", - "items": { - "$ref": "#/$defs/Button" - } - }, - "direction": { - "type": "string", - "enum": [ - "row", - "column" - ] - } - }, - "required": [ - "buttons" - ], - "additionalProperties": false, - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "Button": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "variant": { - "type": "string", - "enum": [ - "primary", - "secondary", - "tertiary" - ] - }, - "type": { - "type": "string", - "enum": [ - "normal", - "destructive" - ] - }, - "size": { - "type": "string", - "enum": [ - "extra-small", - "small", - "medium", - "large" - ] - } - }, - "required": [ - "label" - ], - "additionalProperties": false, - "description": "Clickable button" - }, - "FormControl": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "input": { - "anyOf": [ - { - "$ref": "#/$defs/Input" - }, - { - "$ref": "#/$defs/TextArea" - }, - { - "$ref": "#/$defs/Select" - }, - { - "$ref": "#/$defs/DatePicker" - }, - { - "$ref": "#/$defs/Slider" - }, - { - "$ref": "#/$defs/CheckBoxGroup" - }, - { - "$ref": "#/$defs/RadioGroup" - }, - { - "$ref": "#/$defs/Chips" - }, - { - "$ref": "#/$defs/OptionCards" - } - ] - }, - "hint": { - "type": "string" - } - }, - "required": [ - "label", - "input" - ], - "additionalProperties": false, - "description": "Field with label, input component, and optional hint text" - }, - "Input": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "placeholder": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "text", - "email", - "password", - "number", - "url" - ] - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "TextArea": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "placeholder": { - "type": "string" - }, - "rows": { - "type": "number" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "Select": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/SelectItem" - } - }, - "placeholder": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - }, - "size": { - "type": "string", - "enum": [ - "small", - "medium", - "large" - ] - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "SelectItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false, - "description": "Option for Select" - }, - "DatePicker": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "mode": { - "type": "string", - "enum": [ - "single", - "range" - ] - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": {} - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "Slider": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "variant": { - "type": "string", - "enum": [ - "continuous", - "discrete" - ] - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "step": { - "type": "number" - }, - "defaultValue": { - "type": "array", - "items": { - "type": "number" - } - }, - "label": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "name", - "variant", - "min", - "max" - ], - "additionalProperties": false, - "description": "Numeric slider input; supports continuous and discrete (stepped) variants" - }, - "CheckBoxGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/CheckBoxItem" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": { - "type": "boolean" - } - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "CheckBoxItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "defaultChecked": { - "type": "boolean" - } - }, - "required": [ - "label", - "description", - "name" - ], - "additionalProperties": false - }, - "RadioGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/RadioItem" - } - }, - "defaultValue": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "RadioItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "value": { - "type": "string" - } - }, - "required": [ - "label", - "description", - "value" - ], - "additionalProperties": false - }, - "Chips": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "type": { - "default": "multiple", - "type": "string", - "enum": [ - "single", - "multiple" - ] - }, - "items": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/ChipItem" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "defaultValue": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - } - }, - "required": [ - "name", - "type", - "items" - ], - "additionalProperties": false, - "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." - }, - "ChipItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "disabled": { - "type": "boolean" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false, - "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." - }, - "Icon": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "category": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false, - "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." - }, - "OptionCards": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "type": { - "default": "single", - "type": "string", - "enum": [ - "single", - "multiple" - ] - }, - "items": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/OptionCard" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "defaultValue": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - } - }, - "required": [ - "name", - "type", - "items" - ], - "additionalProperties": false, - "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." - }, - "OptionCard": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "topContent": { - "anyOf": [ - { - "$ref": "#/$defs/Icon" - }, - { - "$ref": "#/$defs/Image" - } - ] - }, - "disabled": { - "type": "boolean" - } - }, - "required": [ - "value", - "title" - ], - "additionalProperties": false, - "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." - }, - "IconButton": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "variant": { - "type": "string", - "enum": [ - "primary", - "secondary", - "tertiary" - ] - }, - "size": { - "type": "string", - "enum": [ - "extra-small", - "small", - "medium", - "large" - ] - }, - "shape": { - "type": "string", - "enum": [ - "square", - "circle" - ] - } - }, - "required": [ - "name", - "icon" - ], - "additionalProperties": false, - "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." - }, - "Steps": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/StepsItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Step-by-step guide" - }, - "StepsItem": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "details": { - "type": "string" - } - }, - "required": [ - "title", - "details" - ], - "additionalProperties": false, - "description": "title and details text for one step" - }, - "InlineHeader": { - "type": "object", - "properties": { - "heading": { - "type": "string" - }, - "description": { - "type": "string" - } - }, - "required": [ - "heading" - ], - "additionalProperties": false, - "description": "Compact section heading with an optional one-line description, for use inside cards." - }, - "EntityList": { - "type": "object", - "properties": { - "rows": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - } - }, - "size": { - "default": "default", - "type": "string", - "enum": [ - "small", - "default" - ] - }, - "header": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - }, - "footer": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - } - }, - "required": [ - "rows", - "size" - ], - "additionalProperties": false, - "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." - }, - "EditableTable": { - "type": "object", - "properties": { - "name": { - "default": "", - "type": "string" - }, - "columns": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "text", - "number", - "date-single", - "select", - "url" - ] - }, - "key": { - "default": "default", - "type": "string" - }, - "header": { - "default": "", - "type": "string" - }, - "width": { - "type": "number" - }, - "options": { - "type": "array", - "items": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false - } - } - }, - "required": [ - "type", - "key", - "header" - ], - "additionalProperties": false - } - }, - "data": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - } - } - }, - "required": [ - "id", - "values" - ], - "additionalProperties": false - } - } - }, - "required": [ - "name", - "columns", - "data" - ], - "additionalProperties": false, - "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" - }, - "SnippetCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/SnippetCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." - }, - "SnippetCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "lhs": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - } - ] - }, - "rhs": { - "anyOf": [ - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/BoldText" - } - ] - } - }, - "required": [ - "lhs" - ], - "additionalProperties": false, - "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." - }, - "IconText": { - "type": "object", - "properties": { - "icon": { - "$ref": "#/$defs/Icon" - }, - "iconVariant": { - "default": "neutral", - "type": "string", - "enum": [ - "neutral", - "info", - "success", - "warning", - "danger", - "inverted", - "filled", - "soft" - ] - }, - "iconSize": { - "default": "m", - "type": "string", - "enum": [ - "xs", - "s", - "m", - "l", - "xl", - "sm", - "md", - "lg" - ] - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - }, - "layout": { - "default": "horizontal", - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - } - }, - "required": [ - "icon", - "iconVariant", - "iconSize", - "title", - "bold", - "layout" - ], - "additionalProperties": false, - "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." - }, - "ImageText": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - }, - "layout": { - "default": "horizontal", - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - }, - "imageSize": { - "type": "number" - } - }, - "required": [ - "src", - "title", - "bold", - "layout" - ], - "additionalProperties": false, - "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." - }, - "Text": { - "type": "object", - "properties": { - "variant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - }, - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "subtextVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number", - "metric" - ] - }, - "size": { - "default": "sm", - "type": "string", - "enum": [ - "xs", - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "variant", - "value", - "subtextVariant", - "size" - ], - "additionalProperties": false, - "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "BoldText": { - "type": "object", - "properties": { - "variant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - }, - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "subtextVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number", - "metric" - ] - }, - "size": { - "default": "sm", - "type": "string", - "enum": [ - "xs", - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "variant", - "value", - "subtextVariant", - "size" - ], - "additionalProperties": false, - "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "OverviewCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/OverviewCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." - }, - "OverviewCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "top": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - }, - { - "$ref": "#/$defs/Text" - } - ] - }, - "bottom": { - "$ref": "#/$defs/MetricIndicatorInline" - } - }, - "required": [ - "top" - ], - "additionalProperties": false, - "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." - }, - "MetricIndicatorInline": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "trend": { - "type": "object", - "properties": { - "direction": { - "type": "string", - "enum": [ - "up", - "down" - ] - }, - "value": { - "type": "number" - } - }, - "required": [ - "direction", - "value" - ], - "additionalProperties": false - } - }, - "required": [ - "value" - ], - "additionalProperties": false, - "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." - }, - "ContextCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/ContextCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." - }, - "ContextCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "title": { - "anyOf": [ - { - "type": "string" - }, - { - "$ref": "#/$defs/Tag" - } - ] - }, - "body": { - "type": "string" - }, - "bgColor": { - "type": "string", - "enum": [ - "gray" - ] - }, - "bgImageSrc": { - "type": "string" - }, - "bgImageAlt": { - "type": "string" - } - }, - "required": [ - "title" - ], - "additionalProperties": false, - "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." - }, - "Tag": { - "type": "object", - "properties": { - "text": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - }, - "variant": { - "type": "string", - "enum": [ - "neutral", - "info", - "success", - "warning", - "danger" - ] - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Styled tag/badge with optional Icon and variant" - }, - "CompositeCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/CompositeCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." - }, - "CompositeCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "header": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - }, - { - "$ref": "#/$defs/ImageTextLarge" - }, - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/Image" - } - ] - }, - "body": { - "default": [], - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/BoldText" - }, - { - "$ref": "#/$defs/MetricIndicatorInline" - }, - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/ListBlock" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/EntityList" - } - ] - } - }, - "footer": { - "type": "object", - "properties": { - "price": { - "anyOf": [ - { - "$ref": "#/$defs/BoldText" - }, - { - "$ref": "#/$defs/MetricIndicatorWithStrikethrough" - } - ] - }, - "button": { - "$ref": "#/$defs/Button" - } - }, - "additionalProperties": false - } - }, - "required": [ - "body" - ], - "additionalProperties": false, - "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." - }, - "ImageTextLarge": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - } - }, - "required": [ - "src", - "title", - "bold" - ], - "additionalProperties": false, - "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." - }, - "ListBlock": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/ListItem" - } - }, - "variant": { - "type": "string", - "enum": [ - "number", - "image" - ] - }, - "size": { - "type": "string", - "enum": [ - "default", - "small" - ] - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." - }, - "ListItem": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "image": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - } - }, - "required": [ - "src", - "alt" - ], - "additionalProperties": false - }, - "actionLabel": { - "type": "string" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "title" - ], - "additionalProperties": false, - "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." - }, - "MetricIndicatorWithStrikethrough": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "previousValue": { - "type": "string" - }, - "trend": { - "type": "object", - "properties": { - "direction": { - "type": "string", - "enum": [ - "up", - "down" - ] - }, - "value": { - "type": "number" - } - }, - "required": [ - "direction", - "value" - ], - "additionalProperties": false - } - }, - "required": [ - "value" - ], - "additionalProperties": false, - "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." - }, - "VisualCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/VisualCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." - }, - "VisualCardItem": { - "type": "object", - "properties": { - "body": { - "$ref": "#/$defs/BoldText" - }, - "id": { - "type": "string" - }, - "bgImageSrc": { - "type": "string" - }, - "tag": { - "$ref": "#/$defs/Tag" - }, - "bgImageAlt": { - "type": "string" - } - }, - "required": [ - "body" - ], - "additionalProperties": false, - "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." - }, - "FollowUpBlock": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/FollowUpItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "List of clickable follow-up suggestions placed at the end of a response" - }, - "FollowUpItem": { - "type": "object", - "properties": { - "text": { - "type": "string" - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Clickable follow-up suggestion — when clicked, sends text as user message" - }, - "SectionBlock": { - "type": "object", - "properties": { - "sections": { - "type": "array", - "items": { - "$ref": "#/$defs/SectionItem" - } - }, - "isFoldable": { - "type": "boolean" - } - }, - "required": [ - "sections" - ], - "additionalProperties": false, - "description": "Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section." - }, - "SectionItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "trigger": { - "type": "string" - }, - "content": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - }, - { - "$ref": "#/$defs/ListBlock" - }, - { - "$ref": "#/$defs/FollowUpBlock" - }, - { - "$ref": "#/$defs/Tabs" - }, - { - "$ref": "#/$defs/Accordion" - } - ] - } - } - }, - "required": [ - "value", - "trigger", - "content" - ], - "additionalProperties": false, - "description": "Section with a label and collapsible content — used inside SectionBlock" - }, - "Tabs": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/TabItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Tabbed container" - }, - "TabItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "trigger": { - "type": "string" - }, - "content": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - }, - { - "$ref": "#/$defs/ListBlock" - }, - { - "$ref": "#/$defs/FollowUpBlock" - }, - { - "$ref": "#/$defs/Accordion" - } - ] - } - } - }, - "required": [ - "value", - "trigger", - "content" - ], - "additionalProperties": false, - "description": "value is unique id, trigger is tab label, content is array of components" - }, - "Accordion": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/AccordionItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Collapsible sections" - }, - "AccordionItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "trigger": { - "type": "string" - }, - "content": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - }, - { - "$ref": "#/$defs/ListBlock" - }, - { - "$ref": "#/$defs/FollowUpBlock" - } - ] - } - } - }, - "required": [ - "value", - "trigger", - "content" - ], - "additionalProperties": false, - "description": "value is unique id, trigger is section title" - }, - "Carousel": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - }, - { - "$ref": "#/$defs/ListBlock" - }, - { - "$ref": "#/$defs/FollowUpBlock" - } - ] - } - } - }, - "variant": { - "type": "string", - "enum": [ - "card", - "sunk" - ] - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Horizontal scrollable carousel" - }, - "Slice": { - "type": "object", - "properties": { - "category": { - "type": "string" - }, - "value": { - "type": "number" - } - }, - "required": [ - "category", - "value" - ], - "additionalProperties": false, - "description": "One slice with label and numeric value" - }, - "Label": { - "type": "object", - "properties": { - "text": { - "type": "string" - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Text label" - }, - "SwitchGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/SwitchItem" - } - }, - "variant": { - "type": "string", - "enum": [ - "clear", - "card", - "sunk" - ] - }, - "value": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": { - "type": "boolean" - } - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false, - "description": "Group of switch toggles" - }, - "SwitchItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "defaultChecked": { - "type": "boolean" - } - }, - "required": [ - "name" - ], - "additionalProperties": false, - "description": "Individual switch toggle" - } - } - }, - "root": "Card", - "reactive": { - "Callout": [ - "visible" - ], - "Input": [ - "value" - ], - "TextArea": [ - "value" - ], - "Select": [ - "value" - ], - "DatePicker": [ - "value" - ], - "Slider": [ - "value" - ], - "CheckBoxGroup": [ - "value" - ], - "RadioGroup": [ - "value" - ], - "SwitchGroup": [ - "value" - ] - } - }, - "openui": { - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "Card": { - "$ref": "#/$defs/Card" - }, - "CardHeader": { - "$ref": "#/$defs/CardHeader" - }, - "TextContent": { - "$ref": "#/$defs/TextContent" - }, - "MarkDownRenderer": { - "$ref": "#/$defs/MarkDownRenderer" - }, - "Callout": { - "$ref": "#/$defs/Callout" - }, - "TextCallout": { - "$ref": "#/$defs/TextCallout" - }, - "Image": { - "$ref": "#/$defs/Image" - }, - "ImageBlock": { - "$ref": "#/$defs/ImageBlock" - }, - "ImageGallery": { - "$ref": "#/$defs/ImageGallery" - }, - "CodeBlock": { - "$ref": "#/$defs/CodeBlock" - }, - "InlineHeader": { - "$ref": "#/$defs/InlineHeader" - }, - "Table": { - "$ref": "#/$defs/Table" - }, - "Col": { - "$ref": "#/$defs/Col" - }, - "EditableTable": { - "$ref": "#/$defs/EditableTable" - }, - "BarChart": { - "$ref": "#/$defs/BarChart" - }, - "LineChart": { - "$ref": "#/$defs/LineChart" - }, - "AreaChart": { - "$ref": "#/$defs/AreaChart" - }, - "RadarChart": { - "$ref": "#/$defs/RadarChart" - }, - "HorizontalBarChart": { - "$ref": "#/$defs/HorizontalBarChart" - }, - "Series": { - "$ref": "#/$defs/Series" - }, - "PieChart": { - "$ref": "#/$defs/PieChart" - }, - "RadialChart": { - "$ref": "#/$defs/RadialChart" - }, - "SingleStackedBarChart": { - "$ref": "#/$defs/SingleStackedBarChart" - }, - "Slice": { - "$ref": "#/$defs/Slice" - }, - "ScatterChart": { - "$ref": "#/$defs/ScatterChart" - }, - "ScatterSeries": { - "$ref": "#/$defs/ScatterSeries" - }, - "Point": { - "$ref": "#/$defs/Point" - }, - "Form": { - "$ref": "#/$defs/Form" - }, - "FormControl": { - "$ref": "#/$defs/FormControl" - }, - "Label": { - "$ref": "#/$defs/Label" - }, - "Input": { - "$ref": "#/$defs/Input" - }, - "TextArea": { - "$ref": "#/$defs/TextArea" - }, - "Select": { - "$ref": "#/$defs/Select" - }, - "SelectItem": { - "$ref": "#/$defs/SelectItem" - }, - "DatePicker": { - "$ref": "#/$defs/DatePicker" - }, - "Slider": { - "$ref": "#/$defs/Slider" - }, - "CheckBoxGroup": { - "$ref": "#/$defs/CheckBoxGroup" - }, - "CheckBoxItem": { - "$ref": "#/$defs/CheckBoxItem" - }, - "RadioGroup": { - "$ref": "#/$defs/RadioGroup" - }, - "RadioItem": { - "$ref": "#/$defs/RadioItem" - }, - "SwitchGroup": { - "$ref": "#/$defs/SwitchGroup" - }, - "SwitchItem": { - "$ref": "#/$defs/SwitchItem" - }, - "ChipItem": { - "$ref": "#/$defs/ChipItem" - }, - "Chips": { - "$ref": "#/$defs/Chips" - }, - "OptionCard": { - "$ref": "#/$defs/OptionCard" - }, - "OptionCards": { - "$ref": "#/$defs/OptionCards" - }, - "Button": { - "$ref": "#/$defs/Button" - }, - "Buttons": { - "$ref": "#/$defs/Buttons" - }, - "IconButton": { - "$ref": "#/$defs/IconButton" - }, - "Stack": { - "$ref": "#/$defs/Stack" - }, - "Tabs": { - "$ref": "#/$defs/Tabs" - }, - "TabItem": { - "$ref": "#/$defs/TabItem" - }, - "Accordion": { - "$ref": "#/$defs/Accordion" - }, - "AccordionItem": { - "$ref": "#/$defs/AccordionItem" - }, - "Steps": { - "$ref": "#/$defs/Steps" - }, - "StepsItem": { - "$ref": "#/$defs/StepsItem" - }, - "Carousel": { - "$ref": "#/$defs/Carousel" - }, - "Separator": { - "$ref": "#/$defs/Separator" - }, - "TagBlock": { - "$ref": "#/$defs/TagBlock" - }, - "Tag": { - "$ref": "#/$defs/Tag" - }, - "Icon": { - "$ref": "#/$defs/Icon" - }, - "EntityList": { - "$ref": "#/$defs/EntityList" - }, - "ListBlock": { - "$ref": "#/$defs/ListBlock" - }, - "ListItem": { - "$ref": "#/$defs/ListItem" - }, - "Text": { - "$ref": "#/$defs/Text" - }, - "BoldText": { - "$ref": "#/$defs/BoldText" - }, - "IconText": { - "$ref": "#/$defs/IconText" - }, - "ImageText": { - "$ref": "#/$defs/ImageText" - }, - "ImageTextLarge": { - "$ref": "#/$defs/ImageTextLarge" - }, - "MetricIndicatorInline": { - "$ref": "#/$defs/MetricIndicatorInline" - }, - "MetricIndicatorWithStrikethrough": { - "$ref": "#/$defs/MetricIndicatorWithStrikethrough" - }, - "SnippetCardItem": { - "$ref": "#/$defs/SnippetCardItem" - }, - "SnippetCardBlock": { - "$ref": "#/$defs/SnippetCardBlock" - }, - "OverviewCardItem": { - "$ref": "#/$defs/OverviewCardItem" - }, - "OverviewCardBlock": { - "$ref": "#/$defs/OverviewCardBlock" - }, - "ContextCardItem": { - "$ref": "#/$defs/ContextCardItem" - }, - "ContextCardBlock": { - "$ref": "#/$defs/ContextCardBlock" - }, - "CompositeCardItem": { - "$ref": "#/$defs/CompositeCardItem" - }, - "CompositeCardBlock": { - "$ref": "#/$defs/CompositeCardBlock" - }, - "VisualCardItem": { - "$ref": "#/$defs/VisualCardItem" - }, - "VisualCardBlock": { - "$ref": "#/$defs/VisualCardBlock" - }, - "Modal": { - "$ref": "#/$defs/Modal" - } - }, - "required": [ - "Card", - "CardHeader", - "TextContent", - "MarkDownRenderer", - "Callout", - "TextCallout", - "Image", - "ImageBlock", - "ImageGallery", - "CodeBlock", - "InlineHeader", - "Table", - "Col", - "EditableTable", - "BarChart", - "LineChart", - "AreaChart", - "RadarChart", - "HorizontalBarChart", - "Series", - "PieChart", - "RadialChart", - "SingleStackedBarChart", - "Slice", - "ScatterChart", - "ScatterSeries", - "Point", - "Form", - "FormControl", - "Label", - "Input", - "TextArea", - "Select", - "SelectItem", - "DatePicker", - "Slider", - "CheckBoxGroup", - "CheckBoxItem", - "RadioGroup", - "RadioItem", - "SwitchGroup", - "SwitchItem", - "ChipItem", - "Chips", - "OptionCard", - "OptionCards", - "Button", - "Buttons", - "IconButton", - "Stack", - "Tabs", - "TabItem", - "Accordion", - "AccordionItem", - "Steps", - "StepsItem", - "Carousel", - "Separator", - "TagBlock", - "Tag", - "Icon", - "EntityList", - "ListBlock", - "ListItem", - "Text", - "BoldText", - "IconText", - "ImageText", - "ImageTextLarge", - "MetricIndicatorInline", - "MetricIndicatorWithStrikethrough", - "SnippetCardItem", - "SnippetCardBlock", - "OverviewCardItem", - "OverviewCardBlock", - "ContextCardItem", - "ContextCardBlock", - "CompositeCardItem", - "CompositeCardBlock", - "VisualCardItem", - "VisualCardBlock", - "Modal" - ], - "additionalProperties": false, - "$defs": { - "Card": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - }, - { - "$ref": "#/$defs/Tabs" - }, - { - "$ref": "#/$defs/Carousel" - }, - { - "$ref": "#/$defs/Stack" - } - ] - } - }, - "variant": { - "type": "string", - "enum": [ - "card", - "sunk", - "clear" - ] - }, - "direction": { - "type": "string", - "enum": [ - "row", - "column" - ] - }, - "gap": { - "type": "string", - "enum": [ - "none", - "xs", - "s", - "m", - "l", - "xl", - "2xl" - ] - }, - "align": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "stretch", - "baseline" - ] - }, - "justify": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "between", - "around", - "evenly" - ] - }, - "wrap": { - "type": "boolean" - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts." - }, - "TextContent": { - "type": "object", - "properties": { - "text": { - "type": "string" - }, - "size": { - "type": "string", - "enum": [ - "small", - "default", - "large", - "small-heavy", - "large-heavy" - ] - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"." - }, - "MarkDownRenderer": { - "type": "object", - "properties": { - "textMarkdown": { - "type": "string" - }, - "variant": { - "type": "string", - "enum": [ - "clear", - "card", - "sunk" - ] - } - }, - "required": [ - "textMarkdown" - ], - "additionalProperties": false, - "description": "Renders markdown text with optional container variant" - }, - "CardHeader": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - } - }, - "additionalProperties": false, - "description": "Header with optional title and subtitle" - }, - "Callout": { - "type": "object", - "properties": { - "variant": { - "type": "string", - "enum": [ - "info", - "warning", - "error", - "success", - "neutral" - ] - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "visible": { - "type": "boolean" - } - }, - "required": [ - "variant", - "title", - "description" - ], - "additionalProperties": false, - "description": "Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false." - }, - "TextCallout": { - "type": "object", - "properties": { - "variant": { - "type": "string", - "enum": [ - "neutral", - "info", - "warning", - "success", - "danger" - ] - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - } - }, - "additionalProperties": false, - "description": "Text callout with variant, title, and description" - }, - "CodeBlock": { - "type": "object", - "properties": { - "language": { - "type": "string" - }, - "codeString": { - "type": "string" - } - }, - "required": [ - "language", - "codeString" - ], - "additionalProperties": false, - "description": "Syntax-highlighted code block" - }, - "Image": { - "type": "object", - "properties": { - "alt": { - "type": "string" - }, - "src": { - "type": "string" - } - }, - "required": [ - "alt" - ], - "additionalProperties": false, - "description": "Image with alt text and optional URL" - }, - "ImageBlock": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - } - }, - "required": [ - "src" - ], - "additionalProperties": false, - "description": "Image block with loading state" - }, - "ImageGallery": { - "type": "object", - "properties": { - "images": { - "type": "array", - "items": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "details": { - "type": "string" - } - }, - "required": [ - "src" - ], - "additionalProperties": false - } - } - }, - "required": [ - "images" - ], - "additionalProperties": false, - "description": "Gallery grid of images with modal preview" - }, - "Separator": { - "type": "object", - "properties": { - "orientation": { - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - }, - "decorative": { - "type": "boolean" - } - }, - "additionalProperties": false, - "description": "Visual divider between content sections" - }, - "HorizontalBarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "grouped", - "stacked" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Horizontal bars; prefer when category labels are long or for ranked lists" - }, - "Series": { - "type": "object", - "properties": { - "category": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "category", - "values" - ], - "additionalProperties": false, - "description": "One data series" - }, - "RadarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Spider/web chart; use for comparing multiple variables across one or more entities" - }, - "PieChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - }, - "variant": { - "type": "string", - "enum": [ - "pie", - "donut" - ] - }, - "appearance": { - "type": "string", - "enum": [ - "circular", - "semiCircular" - ] - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Circular slices; use plucked arrays: PieChart(data.categories, data.values)" - }, - "RadialChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Radial bars; use plucked arrays: RadialChart(data.categories, data.values)" - }, - "SingleStackedBarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "labels", - "values" - ], - "additionalProperties": false, - "description": "Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)" - }, - "ScatterChart": { - "type": "object", - "properties": { - "datasets": { - "type": "array", - "items": { - "$ref": "#/$defs/ScatterSeries" - } - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - } - }, - "required": [ - "datasets" - ], - "additionalProperties": false, - "description": "X/Y scatter plot; use for correlations, distributions, and clustering" - }, - "ScatterSeries": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "points": { - "type": "array", - "items": { - "$ref": "#/$defs/Point" - } - } - }, - "required": [ - "name", - "points" - ], - "additionalProperties": false, - "description": "Named dataset" - }, - "Point": { - "type": "object", - "properties": { - "x": { - "type": "number" - }, - "y": { - "type": "number" - }, - "z": { - "type": "number" - } - }, - "required": [ - "x", - "y" - ], - "additionalProperties": false, - "description": "Data point with numeric coordinates" - }, - "AreaChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "linear", - "natural", - "step" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Filled area under lines; use for cumulative totals or volume trends over time" - }, - "BarChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "grouped", - "stacked" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Vertical bars; use for comparing values across categories with one or more series" - }, - "LineChart": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "series": { - "type": "array", - "items": { - "$ref": "#/$defs/Series" - } - }, - "variant": { - "type": "string", - "enum": [ - "linear", - "natural", - "step" - ] - }, - "xLabel": { - "type": "string" - }, - "yLabel": { - "type": "string" - }, - "height": { - "type": "number" - } - }, - "required": [ - "labels", - "series" - ], - "additionalProperties": false, - "description": "Lines over categories; use for trends and continuous data over time" - }, - "Table": { - "type": "object", - "properties": { - "columns": { - "type": "array", - "items": { - "$ref": "#/$defs/Col" - } - } - }, - "required": [ - "columns" - ], - "additionalProperties": false, - "description": "Data table — column-oriented. Each Col holds its own data array." - }, - "Col": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "data": {}, - "type": { - "type": "string", - "enum": [ - "string", - "number", - "action" - ] - } - }, - "required": [ - "label", - "data" - ], - "additionalProperties": false, - "description": "Column definition — holds label + data array" - }, - "TagBlock": { - "type": "object", - "properties": { - "tags": { - "type": "array", - "items": { - "type": "string" - } - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "tags" - ], - "additionalProperties": false, - "description": "tags is an array of strings; optional size sm | md | lg" - }, - "Form": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "buttons": { - "$ref": "#/$defs/Buttons" - }, - "fields": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/FormControl" - } - } - }, - "required": [ - "name", - "buttons", - "fields" - ], - "additionalProperties": false, - "description": "Form container with fields and explicit action buttons" - }, - "Buttons": { - "type": "object", - "properties": { - "buttons": { - "type": "array", - "items": { - "$ref": "#/$defs/Button" - } - }, - "direction": { - "type": "string", - "enum": [ - "row", - "column" - ] - } - }, - "required": [ - "buttons" - ], - "additionalProperties": false, - "description": "Group of Button components. direction: \"row\" (default) | \"column\"." - }, - "Button": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "variant": { - "type": "string", - "enum": [ - "primary", - "secondary", - "tertiary" - ] - }, - "type": { - "type": "string", - "enum": [ - "normal", - "destructive" - ] - }, - "size": { - "type": "string", - "enum": [ - "extra-small", - "small", - "medium", - "large" - ] - } - }, - "required": [ - "label" - ], - "additionalProperties": false, - "description": "Clickable button" - }, - "FormControl": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "input": { - "anyOf": [ - { - "$ref": "#/$defs/Input" - }, - { - "$ref": "#/$defs/TextArea" - }, - { - "$ref": "#/$defs/Select" - }, - { - "$ref": "#/$defs/DatePicker" - }, - { - "$ref": "#/$defs/Slider" - }, - { - "$ref": "#/$defs/CheckBoxGroup" - }, - { - "$ref": "#/$defs/RadioGroup" - }, - { - "$ref": "#/$defs/Chips" - }, - { - "$ref": "#/$defs/OptionCards" - } - ] - }, - "hint": { - "type": "string" - } - }, - "required": [ - "label", - "input" - ], - "additionalProperties": false, - "description": "Field with label, input component, and optional hint text" - }, - "Input": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "placeholder": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "text", - "email", - "password", - "number", - "url" - ] - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "TextArea": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "placeholder": { - "type": "string" - }, - "rows": { - "type": "number" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "Select": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/SelectItem" - } - }, - "placeholder": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - }, - "size": { - "type": "string", - "enum": [ - "small", - "medium", - "large" - ] - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "SelectItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false, - "description": "Option for Select" - }, - "DatePicker": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "mode": { - "type": "string", - "enum": [ - "single", - "range" - ] - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": {} - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "Slider": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "variant": { - "type": "string", - "enum": [ - "continuous", - "discrete" - ] - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "step": { - "type": "number" - }, - "defaultValue": { - "type": "array", - "items": { - "type": "number" - } - }, - "label": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "array", - "items": { - "type": "number" - } - } - }, - "required": [ - "name", - "variant", - "min", - "max" - ], - "additionalProperties": false, - "description": "Numeric slider input; supports continuous and discrete (stepped) variants" - }, - "CheckBoxGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/CheckBoxItem" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": { - "type": "boolean" - } - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "CheckBoxItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "defaultChecked": { - "type": "boolean" - } - }, - "required": [ - "label", - "description", - "name" - ], - "additionalProperties": false - }, - "RadioGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/RadioItem" - } - }, - "defaultValue": { - "type": "string" - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "value": { - "type": "string" - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false - }, - "RadioItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "value": { - "type": "string" - } - }, - "required": [ - "label", - "description", - "value" - ], - "additionalProperties": false - }, - "Chips": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "type": { - "default": "multiple", - "type": "string", - "enum": [ - "single", - "multiple" - ] - }, - "items": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/ChipItem" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "defaultValue": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - } - }, - "required": [ - "name", - "type", - "items" - ], - "additionalProperties": false, - "description": "A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`." - }, - "ChipItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "disabled": { - "type": "boolean" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false, - "description": "A single selectable chip inside a Chips group, with a value, label and optional icon." - }, - "Icon": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "category": { - "type": "string" - } - }, - "required": [ - "name" - ], - "additionalProperties": false, - "description": "A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve." - }, - "OptionCards": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "type": { - "default": "single", - "type": "string", - "enum": [ - "single", - "multiple" - ] - }, - "items": { - "default": [], - "type": "array", - "items": { - "$ref": "#/$defs/OptionCard" - } - }, - "rules": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "email": { - "type": "boolean" - }, - "url": { - "type": "boolean" - }, - "numeric": { - "type": "boolean" - }, - "min": { - "type": "number" - }, - "max": { - "type": "number" - }, - "minLength": { - "type": "number" - }, - "maxLength": { - "type": "number" - }, - "pattern": { - "type": "string" - } - }, - "additionalProperties": false - }, - "defaultValue": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - } - }, - "required": [ - "name", - "type", - "items" - ], - "additionalProperties": false, - "description": "A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`." - }, - "OptionCard": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "topContent": { - "anyOf": [ - { - "$ref": "#/$defs/Icon" - }, - { - "$ref": "#/$defs/Image" - } - ] - }, - "disabled": { - "type": "boolean" - } - }, - "required": [ - "value", - "title" - ], - "additionalProperties": false, - "description": "A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top." - }, - "IconButton": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "variant": { - "type": "string", - "enum": [ - "primary", - "secondary", - "tertiary" - ] - }, - "size": { - "type": "string", - "enum": [ - "extra-small", - "small", - "medium", - "large" - ] - }, - "shape": { - "type": "string", - "enum": [ - "square", - "circle" - ] - } - }, - "required": [ - "name", - "icon" - ], - "additionalProperties": false, - "description": "Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click." - }, - "Steps": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/StepsItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Step-by-step guide" - }, - "StepsItem": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "details": { - "type": "string" - } - }, - "required": [ - "title", - "details" - ], - "additionalProperties": false, - "description": "title and details text for one step" - }, - "InlineHeader": { - "type": "object", - "properties": { - "heading": { - "type": "string" - }, - "description": { - "type": "string" - } - }, - "required": [ - "heading" - ], - "additionalProperties": false, - "description": "Compact section heading with an optional one-line description, for use inside cards." - }, - "EntityList": { - "type": "object", - "properties": { - "rows": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - } - }, - "size": { - "default": "default", - "type": "string", - "enum": [ - "small", - "default" - ] - }, - "header": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - }, - "footer": { - "type": "object", - "properties": { - "left": { - "type": "string" - }, - "right": { - "type": "string" - }, - "rightVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - } - }, - "required": [ - "left", - "right", - "rightVariant" - ], - "additionalProperties": false - } - }, - "required": [ - "rows", - "size" - ], - "additionalProperties": false, - "description": "Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers." - }, - "EditableTable": { - "type": "object", - "properties": { - "name": { - "default": "", - "type": "string" - }, - "columns": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "text", - "number", - "date-single", - "select", - "url" - ] - }, - "key": { - "default": "default", - "type": "string" - }, - "header": { - "default": "", - "type": "string" - }, - "width": { - "type": "number" - }, - "options": { - "type": "array", - "items": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "label": { - "type": "string" - } - }, - "required": [ - "value", - "label" - ], - "additionalProperties": false - } - } - }, - "required": [ - "type", - "key", - "header" - ], - "additionalProperties": false - } - }, - "data": { - "default": [], - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - } - } - }, - "required": [ - "id", - "values" - ], - "additionalProperties": false - } - } - }, - "required": [ - "name", - "columns", - "data" - ], - "additionalProperties": false, - "description": "Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field" - }, - "SnippetCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/SnippetCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action." - }, - "SnippetCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "lhs": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - } - ] - }, - "rhs": { - "anyOf": [ - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/BoldText" - } - ] - } - }, - "required": [ - "lhs" - ], - "additionalProperties": false, - "description": "One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)." - }, - "IconText": { - "type": "object", - "properties": { - "icon": { - "$ref": "#/$defs/Icon" - }, - "iconVariant": { - "default": "neutral", - "type": "string", - "enum": [ - "neutral", - "info", - "success", - "warning", - "danger", - "inverted", - "filled", - "soft" - ] - }, - "iconSize": { - "default": "m", - "type": "string", - "enum": [ - "xs", - "s", - "m", - "l", - "xl", - "sm", - "md", - "lg" - ] - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - }, - "layout": { - "default": "horizontal", - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - } - }, - "required": [ - "icon", - "iconVariant", - "iconSize", - "title", - "bold", - "layout" - ], - "additionalProperties": false, - "description": "An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color." - }, - "ImageText": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - }, - "layout": { - "default": "horizontal", - "type": "string", - "enum": [ - "horizontal", - "vertical" - ] - }, - "imageSize": { - "type": "number" - } - }, - "required": [ - "src", - "title", - "bold", - "layout" - ], - "additionalProperties": false, - "description": "A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL." - }, - "Text": { - "type": "object", - "properties": { - "variant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - }, - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "subtextVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number", - "metric" - ] - }, - "size": { - "default": "sm", - "type": "string", - "enum": [ - "xs", - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "variant", - "value", - "subtextVariant", - "size" - ], - "additionalProperties": false, - "description": "Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "BoldText": { - "type": "object", - "properties": { - "variant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number" - ] - }, - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "subtextVariant": { - "default": "text", - "type": "string", - "enum": [ - "text", - "number", - "metric" - ] - }, - "size": { - "default": "sm", - "type": "string", - "enum": [ - "xs", - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "variant", - "value", - "subtextVariant", - "size" - ], - "additionalProperties": false, - "description": "Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red." - }, - "OverviewCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/OverviewCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action." - }, - "OverviewCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "top": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - }, - { - "$ref": "#/$defs/Text" - } - ] - }, - "bottom": { - "$ref": "#/$defs/MetricIndicatorInline" - } - }, - "required": [ - "top" - ], - "additionalProperties": false, - "description": "One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom." - }, - "MetricIndicatorInline": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "trend": { - "type": "object", - "properties": { - "direction": { - "type": "string", - "enum": [ - "up", - "down" - ] - }, - "value": { - "type": "number" - } - }, - "required": [ - "direction", - "value" - ], - "additionalProperties": false - } - }, - "required": [ - "value" - ], - "additionalProperties": false, - "description": "Headline metric value with an optional +/- percentage trend and subtext, all on one line." - }, - "ContextCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/ContextCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable." - }, - "ContextCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "title": { - "anyOf": [ - { - "type": "string" - }, - { - "$ref": "#/$defs/Tag" - } - ] - }, - "body": { - "type": "string" - }, - "bgColor": { - "type": "string", - "enum": [ - "gray" - ] - }, - "bgImageSrc": { - "type": "string" - }, - "bgImageAlt": { - "type": "string" - } - }, - "required": [ - "title" - ], - "additionalProperties": false, - "description": "A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image." - }, - "Tag": { - "type": "object", - "properties": { - "text": { - "type": "string" - }, - "icon": { - "$ref": "#/$defs/Icon" - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - }, - "variant": { - "type": "string", - "enum": [ - "neutral", - "info", - "success", - "warning", - "danger" - ] - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Styled tag/badge with optional Icon and variant" - }, - "CompositeCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/CompositeCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable." - }, - "CompositeCardItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "header": { - "anyOf": [ - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/ImageText" - }, - { - "$ref": "#/$defs/ImageTextLarge" - }, - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/Image" - } - ] - }, - "body": { - "default": [], - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/BoldText" - }, - { - "$ref": "#/$defs/MetricIndicatorInline" - }, - { - "$ref": "#/$defs/IconText" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/ListBlock" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/EntityList" - } - ] - } - }, - "footer": { - "type": "object", - "properties": { - "price": { - "anyOf": [ - { - "$ref": "#/$defs/BoldText" - }, - { - "$ref": "#/$defs/MetricIndicatorWithStrikethrough" - } - ] - }, - "button": { - "$ref": "#/$defs/Button" - } - }, - "additionalProperties": false - } - }, - "required": [ - "body" - ], - "additionalProperties": false, - "description": "A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer." - }, - "ImageTextLarge": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - }, - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "bold": { - "default": false, - "type": "boolean" - } - }, - "required": [ - "src", - "title", - "bold" - ], - "additionalProperties": false, - "description": "A full-width banner image above a bold title and optional subtitle. src must be a real image URL." - }, - "ListBlock": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/ListItem" - } - }, - "variant": { - "type": "string", - "enum": [ - "number", - "image" - ] - }, - "size": { - "type": "string", - "enum": [ - "default", - "small" - ] - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list." - }, - "ListItem": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "subtitle": { - "type": "string" - }, - "image": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "alt": { - "type": "string" - } - }, - "required": [ - "src", - "alt" - ], - "additionalProperties": false - }, - "actionLabel": { - "type": "string" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "title" - ], - "additionalProperties": false, - "description": "Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable." - }, - "MetricIndicatorWithStrikethrough": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "subtext": { - "type": "string" - }, - "previousValue": { - "type": "string" - }, - "trend": { - "type": "object", - "properties": { - "direction": { - "type": "string", - "enum": [ - "up", - "down" - ] - }, - "value": { - "type": "number" - } - }, - "required": [ - "direction", - "value" - ], - "additionalProperties": false - } - }, - "required": [ - "value" - ], - "additionalProperties": false, - "description": "Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below." - }, - "VisualCardBlock": { - "type": "object", - "properties": { - "items": { - "minItems": 2, - "type": "array", - "items": { - "$ref": "#/$defs/VisualCardItem" - } - }, - "layout": { - "default": "grid", - "type": "string", - "enum": [ - "grid", - "carousel" - ] - }, - "responsive": { - "default": true, - "type": "boolean" - }, - "action": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "open_url" - }, - "url": { - "type": "string" - } - }, - "required": [ - "type", - "url" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "continue_conversation" - }, - "context": { - "type": "string" - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "params": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": {} - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - ] - }, - "gap": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "items", - "layout", - "responsive" - ], - "additionalProperties": false, - "description": "A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable." - }, - "VisualCardItem": { - "type": "object", - "properties": { - "body": { - "$ref": "#/$defs/BoldText" - }, - "id": { - "type": "string" - }, - "bgImageSrc": { - "type": "string" - }, - "tag": { - "$ref": "#/$defs/Tag" - }, - "bgImageAlt": { - "type": "string" - } - }, - "required": [ - "body" - ], - "additionalProperties": false, - "description": "A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)." - }, - "Tabs": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/TabItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Tabbed container" - }, - "TabItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "trigger": { - "type": "string" - }, - "content": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - } - }, - "required": [ - "value", - "trigger", - "content" - ], - "additionalProperties": false, - "description": "value is unique id, trigger is tab label, content is array of components" - }, - "Carousel": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - } - }, - "variant": { - "type": "string", - "enum": [ - "card", - "sunk" - ] - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Horizontal scrollable carousel" - }, - "Stack": { - "type": "object", - "properties": { - "children": { - "type": "array", - "items": {} - }, - "direction": { - "type": "string", - "enum": [ - "row", - "column" - ] - }, - "gap": { - "type": "string", - "enum": [ - "none", - "xs", - "s", - "m", - "l", - "xl", - "2xl" - ] - }, - "align": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "stretch", - "baseline" - ] - }, - "justify": { - "type": "string", - "enum": [ - "start", - "center", - "end", - "between", - "around", - "evenly" - ] - }, - "wrap": { - "type": "boolean" - } - }, - "required": [ - "children" - ], - "additionalProperties": false, - "description": "Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"." - }, - "Slice": { - "type": "object", - "properties": { - "category": { - "type": "string" - }, - "value": { - "type": "number" - } - }, - "required": [ - "category", - "value" - ], - "additionalProperties": false, - "description": "One slice with label and numeric value" - }, - "Label": { - "type": "object", - "properties": { - "text": { - "type": "string" - } - }, - "required": [ - "text" - ], - "additionalProperties": false, - "description": "Text label" - }, - "SwitchGroup": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/SwitchItem" - } - }, - "variant": { - "type": "string", - "enum": [ - "clear", - "card", - "sunk" - ] - }, - "value": { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": { - "type": "boolean" - } - } - }, - "required": [ - "name", - "items" - ], - "additionalProperties": false, - "description": "Group of switch toggles" - }, - "SwitchItem": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "defaultChecked": { - "type": "boolean" - } - }, - "required": [ - "name" - ], - "additionalProperties": false, - "description": "Individual switch toggle" - }, - "Accordion": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/$defs/AccordionItem" - } - } - }, - "required": [ - "items" - ], - "additionalProperties": false, - "description": "Collapsible sections" - }, - "AccordionItem": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "trigger": { - "type": "string" - }, - "content": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - } - }, - "required": [ - "value", - "trigger", - "content" - ], - "additionalProperties": false, - "description": "value is unique id, trigger is section title" - }, - "Modal": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "open": { - "type": "boolean" - }, - "children": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/TextContent" - }, - { - "$ref": "#/$defs/MarkDownRenderer" - }, - { - "$ref": "#/$defs/CardHeader" - }, - { - "$ref": "#/$defs/Callout" - }, - { - "$ref": "#/$defs/TextCallout" - }, - { - "$ref": "#/$defs/CodeBlock" - }, - { - "$ref": "#/$defs/Image" - }, - { - "$ref": "#/$defs/ImageBlock" - }, - { - "$ref": "#/$defs/ImageGallery" - }, - { - "$ref": "#/$defs/Separator" - }, - { - "$ref": "#/$defs/HorizontalBarChart" - }, - { - "$ref": "#/$defs/RadarChart" - }, - { - "$ref": "#/$defs/PieChart" - }, - { - "$ref": "#/$defs/RadialChart" - }, - { - "$ref": "#/$defs/SingleStackedBarChart" - }, - { - "$ref": "#/$defs/ScatterChart" - }, - { - "$ref": "#/$defs/AreaChart" - }, - { - "$ref": "#/$defs/BarChart" - }, - { - "$ref": "#/$defs/LineChart" - }, - { - "$ref": "#/$defs/Table" - }, - { - "$ref": "#/$defs/TagBlock" - }, - { - "$ref": "#/$defs/Form" - }, - { - "$ref": "#/$defs/Buttons" - }, - { - "$ref": "#/$defs/IconButton" - }, - { - "$ref": "#/$defs/Steps" - }, - { - "$ref": "#/$defs/InlineHeader" - }, - { - "$ref": "#/$defs/EntityList" - }, - { - "$ref": "#/$defs/EditableTable" - }, - { - "$ref": "#/$defs/SnippetCardBlock" - }, - { - "$ref": "#/$defs/OverviewCardBlock" - }, - { - "$ref": "#/$defs/ContextCardBlock" - }, - { - "$ref": "#/$defs/CompositeCardBlock" - }, - { - "$ref": "#/$defs/VisualCardBlock" - } - ] - } - }, - "size": { - "type": "string", - "enum": [ - "sm", - "md", - "lg" - ] - } - }, - "required": [ - "title", - "children" - ], - "additionalProperties": false, - "description": "Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children." - } - } - }, - "root": "Stack", - "reactive": { - "Callout": [ - "visible" - ], - "Input": [ - "value" - ], - "TextArea": [ - "value" - ], - "Select": [ - "value" - ], - "DatePicker": [ - "value" - ], - "Slider": [ - "value" - ], - "CheckBoxGroup": [ - "value" - ], - "RadioGroup": [ - "value" - ], - "SwitchGroup": [ - "value" - ], - "Modal": [ - "open" - ] - } - }, - "test": { - "schema": { - "$defs": { - "Card": { - "properties": { - "children": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/$defs/Text" - }, - { - "$ref": "#/$defs/Button" - }, - { - "$ref": "#/$defs/Chart" - } - ] - } - }, - "title": { - "type": "string" - } - }, - "required": [ - "children" - ] - }, - "Text": { - "properties": { - "text": { - "type": "string" - }, - "size": { - "type": "string", - "enum": [ - "s", - "m", - "l" - ], - "default": "m" - } - }, - "required": [ - "text" - ] - }, - "Button": { - "properties": { - "label": { - "type": "string" - }, - "action": {}, - "variant": { - "type": "string", - "enum": [ - "primary", - "secondary" - ] - } - }, - "required": [ - "label" - ] - }, - "Input": { - "properties": { - "name": { - "type": "string" - }, - "value": { - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "Chart": { - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "items": { - "type": "number" - } - }, - "meta": { - "type": "object", - "properties": { - "unit": { - "type": "string" - }, - "scale": { - "type": "number", - "default": 1 - } - }, - "required": [ - "unit" - ] - } - }, - "required": [ - "labels", - "values" - ] - }, - "Tagged": { - "properties": { - "count": { - "type": "integer" - }, - "flag": { - "type": "boolean" - }, - "kind": { - "const": "x" - }, - "tone": { - "type": "string", - "default": "neutral" - } - }, - "required": [ - "tone" - ] - } - } - }, - "root": "Card", - "reactive": { - "Input": [ - "value" - ] - } - }, - "hoisted": { - "schema": { - "properties": { - "Tree": {} - }, - "$defs": { - "Tree": { - "properties": { - "node": { - "$ref": "#/$defs/__schema0" - } - }, - "required": [ - "node" - ] - }, - "__schema0": { - "type": "object", - "properties": { - "label": { - "type": "string" - } - } - } - } - }, - "root": "Tree", - "reactive": {} - } +"chat": {"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"Card":{"$ref":"#/$defs/Card"},"CardHeader":{"$ref":"#/$defs/CardHeader"},"TextContent":{"$ref":"#/$defs/TextContent"},"MarkDownRenderer":{"$ref":"#/$defs/MarkDownRenderer"},"Callout":{"$ref":"#/$defs/Callout"},"TextCallout":{"$ref":"#/$defs/TextCallout"},"Image":{"$ref":"#/$defs/Image"},"ImageBlock":{"$ref":"#/$defs/ImageBlock"},"ImageGallery":{"$ref":"#/$defs/ImageGallery"},"CodeBlock":{"$ref":"#/$defs/CodeBlock"},"Separator":{"$ref":"#/$defs/Separator"},"Table":{"$ref":"#/$defs/Table"},"Col":{"$ref":"#/$defs/Col"},"BarChart":{"$ref":"#/$defs/BarChart"},"LineChart":{"$ref":"#/$defs/LineChart"},"AreaChart":{"$ref":"#/$defs/AreaChart"},"RadarChart":{"$ref":"#/$defs/RadarChart"},"HorizontalBarChart":{"$ref":"#/$defs/HorizontalBarChart"},"Series":{"$ref":"#/$defs/Series"},"PieChart":{"$ref":"#/$defs/PieChart"},"RadialChart":{"$ref":"#/$defs/RadialChart"},"SingleStackedBarChart":{"$ref":"#/$defs/SingleStackedBarChart"},"Slice":{"$ref":"#/$defs/Slice"},"ScatterChart":{"$ref":"#/$defs/ScatterChart"},"ScatterSeries":{"$ref":"#/$defs/ScatterSeries"},"Point":{"$ref":"#/$defs/Point"},"Form":{"$ref":"#/$defs/Form"},"FormControl":{"$ref":"#/$defs/FormControl"},"Label":{"$ref":"#/$defs/Label"},"Input":{"$ref":"#/$defs/Input"},"TextArea":{"$ref":"#/$defs/TextArea"},"Select":{"$ref":"#/$defs/Select"},"SelectItem":{"$ref":"#/$defs/SelectItem"},"DatePicker":{"$ref":"#/$defs/DatePicker"},"Slider":{"$ref":"#/$defs/Slider"},"CheckBoxGroup":{"$ref":"#/$defs/CheckBoxGroup"},"CheckBoxItem":{"$ref":"#/$defs/CheckBoxItem"},"RadioGroup":{"$ref":"#/$defs/RadioGroup"},"RadioItem":{"$ref":"#/$defs/RadioItem"},"SwitchGroup":{"$ref":"#/$defs/SwitchGroup"},"SwitchItem":{"$ref":"#/$defs/SwitchItem"},"Button":{"$ref":"#/$defs/Button"},"Buttons":{"$ref":"#/$defs/Buttons"},"ListBlock":{"$ref":"#/$defs/ListBlock"},"ListItem":{"$ref":"#/$defs/ListItem"},"FollowUpBlock":{"$ref":"#/$defs/FollowUpBlock"},"FollowUpItem":{"$ref":"#/$defs/FollowUpItem"},"SectionBlock":{"$ref":"#/$defs/SectionBlock"},"SectionItem":{"$ref":"#/$defs/SectionItem"},"Tabs":{"$ref":"#/$defs/Tabs"},"TabItem":{"$ref":"#/$defs/TabItem"},"Accordion":{"$ref":"#/$defs/Accordion"},"AccordionItem":{"$ref":"#/$defs/AccordionItem"},"Steps":{"$ref":"#/$defs/Steps"},"StepsItem":{"$ref":"#/$defs/StepsItem"},"Carousel":{"$ref":"#/$defs/Carousel"},"TagBlock":{"$ref":"#/$defs/TagBlock"},"Tag":{"$ref":"#/$defs/Tag"},"EntityList":{"$ref":"#/$defs/EntityList"},"InlineHeader":{"$ref":"#/$defs/InlineHeader"},"Icon":{"$ref":"#/$defs/Icon"},"IconButton":{"$ref":"#/$defs/IconButton"},"EditableTable":{"$ref":"#/$defs/EditableTable"},"ChipItem":{"$ref":"#/$defs/ChipItem"},"Chips":{"$ref":"#/$defs/Chips"},"OptionCard":{"$ref":"#/$defs/OptionCard"},"OptionCards":{"$ref":"#/$defs/OptionCards"},"Text":{"$ref":"#/$defs/Text"},"BoldText":{"$ref":"#/$defs/BoldText"},"IconText":{"$ref":"#/$defs/IconText"},"ImageText":{"$ref":"#/$defs/ImageText"},"ImageTextLarge":{"$ref":"#/$defs/ImageTextLarge"},"MetricIndicatorInline":{"$ref":"#/$defs/MetricIndicatorInline"},"MetricIndicatorWithStrikethrough":{"$ref":"#/$defs/MetricIndicatorWithStrikethrough"},"SnippetCardItem":{"$ref":"#/$defs/SnippetCardItem"},"SnippetCardBlock":{"$ref":"#/$defs/SnippetCardBlock"},"OverviewCardItem":{"$ref":"#/$defs/OverviewCardItem"},"OverviewCardBlock":{"$ref":"#/$defs/OverviewCardBlock"},"ContextCardItem":{"$ref":"#/$defs/ContextCardItem"},"ContextCardBlock":{"$ref":"#/$defs/ContextCardBlock"},"CompositeCardItem":{"$ref":"#/$defs/CompositeCardItem"},"CompositeCardBlock":{"$ref":"#/$defs/CompositeCardBlock"},"VisualCardItem":{"$ref":"#/$defs/VisualCardItem"},"VisualCardBlock":{"$ref":"#/$defs/VisualCardBlock"}},"required":["Card","CardHeader","TextContent","MarkDownRenderer","Callout","TextCallout","Image","ImageBlock","ImageGallery","CodeBlock","Separator","Table","Col","BarChart","LineChart","AreaChart","RadarChart","HorizontalBarChart","Series","PieChart","RadialChart","SingleStackedBarChart","Slice","ScatterChart","ScatterSeries","Point","Form","FormControl","Label","Input","TextArea","Select","SelectItem","DatePicker","Slider","CheckBoxGroup","CheckBoxItem","RadioGroup","RadioItem","SwitchGroup","SwitchItem","Button","Buttons","ListBlock","ListItem","FollowUpBlock","FollowUpItem","SectionBlock","SectionItem","Tabs","TabItem","Accordion","AccordionItem","Steps","StepsItem","Carousel","TagBlock","Tag","EntityList","InlineHeader","Icon","IconButton","EditableTable","ChipItem","Chips","OptionCard","OptionCards","Text","BoldText","IconText","ImageText","ImageTextLarge","MetricIndicatorInline","MetricIndicatorWithStrikethrough","SnippetCardItem","SnippetCardBlock","OverviewCardItem","OverviewCardBlock","ContextCardItem","ContextCardBlock","CompositeCardItem","CompositeCardBlock","VisualCardItem","VisualCardBlock"],"additionalProperties":false,"$defs":{"Card":{"type":"object","properties":{"children":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"},{"$ref":"#/$defs/ListBlock"},{"$ref":"#/$defs/FollowUpBlock"},{"$ref":"#/$defs/SectionBlock"},{"$ref":"#/$defs/Tabs"},{"$ref":"#/$defs/Carousel"}]}},"sources":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"title":{"type":"string"},"sourceName":{"type":"string"}},"required":["title","sourceName"],"additionalProperties":false}}},"required":["children"],"additionalProperties":false,"description":"Vertical container for all content in a chat response. Children stack top to bottom automatically. Optional sources ([{ title, sourceName, url }]) render as a Sources strip at the bottom and back inline [n] citations in TextContent."},"TextContent":{"type":"object","properties":{"text":{"type":"string"},"size":{"type":"string","enum":["small","default","large","small-heavy","large-heavy"]}},"required":["text"],"additionalProperties":false,"description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"MarkDownRenderer":{"type":"object","properties":{"textMarkdown":{"type":"string"},"variant":{"type":"string","enum":["clear","card","sunk"]}},"required":["textMarkdown"],"additionalProperties":false,"description":"Renders markdown text with optional container variant"},"CardHeader":{"type":"object","properties":{"title":{"type":"string"},"subtitle":{"type":"string"}},"additionalProperties":false,"description":"Header with optional title and subtitle"},"Callout":{"type":"object","properties":{"variant":{"type":"string","enum":["info","warning","error","success","neutral"]},"title":{"type":"string"},"description":{"type":"string"},"visible":{"type":"boolean"}},"required":["variant","title","description"],"additionalProperties":false,"description":"Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false."},"TextCallout":{"type":"object","properties":{"variant":{"type":"string","enum":["neutral","info","warning","success","danger"]},"title":{"type":"string"},"description":{"type":"string"}},"additionalProperties":false,"description":"Text callout with variant, title, and description"},"CodeBlock":{"type":"object","properties":{"language":{"type":"string"},"codeString":{"type":"string"}},"required":["language","codeString"],"additionalProperties":false,"description":"Syntax-highlighted code block"},"Image":{"type":"object","properties":{"alt":{"type":"string"},"src":{"type":"string"}},"required":["alt"],"additionalProperties":false,"description":"Image with alt text and optional URL"},"ImageBlock":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"}},"required":["src"],"additionalProperties":false,"description":"Image block with loading state"},"ImageGallery":{"type":"object","properties":{"images":{"type":"array","items":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"details":{"type":"string"}},"required":["src"],"additionalProperties":false}}},"required":["images"],"additionalProperties":false,"description":"Gallery grid of images with modal preview"},"Separator":{"type":"object","properties":{"orientation":{"type":"string","enum":["horizontal","vertical"]},"decorative":{"type":"boolean"}},"additionalProperties":false,"description":"Visual divider between content sections"},"HorizontalBarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["grouped","stacked"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"}},"required":["labels","series"],"additionalProperties":false,"description":"Horizontal bars; prefer when category labels are long or for ranked lists"},"Series":{"type":"object","properties":{"category":{"type":"string"},"values":{"type":"array","items":{"type":"number"}}},"required":["category","values"],"additionalProperties":false,"description":"One data series"},"RadarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}}},"required":["labels","series"],"additionalProperties":false,"description":"Spider/web chart; use for comparing multiple variables across one or more entities"},"PieChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}},"variant":{"type":"string","enum":["pie","donut"]},"appearance":{"type":"string","enum":["circular","semiCircular"]}},"required":["labels","values"],"additionalProperties":false,"description":"Circular slices; use plucked arrays: PieChart(data.categories, data.values)"},"RadialChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}}},"required":["labels","values"],"additionalProperties":false,"description":"Radial bars; use plucked arrays: RadialChart(data.categories, data.values)"},"SingleStackedBarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}}},"required":["labels","values"],"additionalProperties":false,"description":"Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)"},"ScatterChart":{"type":"object","properties":{"datasets":{"type":"array","items":{"$ref":"#/$defs/ScatterSeries"}},"xLabel":{"type":"string"},"yLabel":{"type":"string"}},"required":["datasets"],"additionalProperties":false,"description":"X/Y scatter plot; use for correlations, distributions, and clustering"},"ScatterSeries":{"type":"object","properties":{"name":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/$defs/Point"}}},"required":["name","points"],"additionalProperties":false,"description":"Named dataset"},"Point":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}},"required":["x","y"],"additionalProperties":false,"description":"Data point with numeric coordinates"},"AreaChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["linear","natural","step"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Filled area under lines; use for cumulative totals or volume trends over time"},"BarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["grouped","stacked"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Vertical bars; use for comparing values across categories with one or more series"},"LineChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["linear","natural","step"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Lines over categories; use for trends and continuous data over time"},"Table":{"type":"object","properties":{"columns":{"type":"array","items":{"$ref":"#/$defs/Col"}}},"required":["columns"],"additionalProperties":false,"description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"type":"object","properties":{"label":{"type":"string"},"data":{},"type":{"type":"string","enum":["string","number","action"]}},"required":["label","data"],"additionalProperties":false,"description":"Column definition — holds label + data array"},"TagBlock":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"}},"size":{"type":"string","enum":["sm","md","lg"]}},"required":["tags"],"additionalProperties":false,"description":"tags is an array of strings; optional size sm | md | lg"},"Form":{"type":"object","properties":{"name":{"type":"string"},"buttons":{"$ref":"#/$defs/Buttons"},"fields":{"default":[],"type":"array","items":{"$ref":"#/$defs/FormControl"}}},"required":["name","buttons","fields"],"additionalProperties":false,"description":"Form container with fields and explicit action buttons"},"Buttons":{"type":"object","properties":{"buttons":{"type":"array","items":{"$ref":"#/$defs/Button"}},"direction":{"type":"string","enum":["row","column"]}},"required":["buttons"],"additionalProperties":false,"description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"Button":{"type":"object","properties":{"label":{"type":"string"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"variant":{"type":"string","enum":["primary","secondary","tertiary"]},"type":{"type":"string","enum":["normal","destructive"]},"size":{"type":"string","enum":["extra-small","small","medium","large"]}},"required":["label"],"additionalProperties":false,"description":"Clickable button"},"FormControl":{"type":"object","properties":{"label":{"type":"string"},"input":{"anyOf":[{"$ref":"#/$defs/Input"},{"$ref":"#/$defs/TextArea"},{"$ref":"#/$defs/Select"},{"$ref":"#/$defs/DatePicker"},{"$ref":"#/$defs/Slider"},{"$ref":"#/$defs/CheckBoxGroup"},{"$ref":"#/$defs/RadioGroup"},{"$ref":"#/$defs/Chips"},{"$ref":"#/$defs/OptionCards"}]},"hint":{"type":"string"}},"required":["label","input"],"additionalProperties":false,"description":"Field with label, input component, and optional hint text"},"Input":{"type":"object","properties":{"name":{"type":"string"},"placeholder":{"type":"string"},"type":{"type":"string","enum":["text","email","password","number","url"]},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name"],"additionalProperties":false},"TextArea":{"type":"object","properties":{"name":{"type":"string"},"placeholder":{"type":"string"},"rows":{"type":"number"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name"],"additionalProperties":false},"Select":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/SelectItem"}},"placeholder":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"},"size":{"type":"string","enum":["small","medium","large"]}},"required":["name","items"],"additionalProperties":false},"SelectItem":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}},"required":["value","label"],"additionalProperties":false,"description":"Option for Select"},"DatePicker":{"type":"object","properties":{"name":{"type":"string"},"mode":{"type":"string","enum":["single","range"]},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{}},"required":["name"],"additionalProperties":false},"Slider":{"type":"object","properties":{"name":{"type":"string"},"variant":{"type":"string","enum":["continuous","discrete"]},"min":{"type":"number"},"max":{"type":"number"},"step":{"type":"number"},"defaultValue":{"type":"array","items":{"type":"number"}},"label":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"array","items":{"type":"number"}}},"required":["name","variant","min","max"],"additionalProperties":false,"description":"Numeric slider input; supports continuous and discrete (stepped) variants"},"CheckBoxGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/CheckBoxItem"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"boolean"}}},"required":["name","items"],"additionalProperties":false},"CheckBoxItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"},"defaultChecked":{"type":"boolean"}},"required":["label","description","name"],"additionalProperties":false},"RadioGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/RadioItem"}},"defaultValue":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name","items"],"additionalProperties":false},"RadioItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"value":{"type":"string"}},"required":["label","description","value"],"additionalProperties":false},"Chips":{"type":"object","properties":{"name":{"type":"string"},"type":{"default":"multiple","type":"string","enum":["single","multiple"]},"items":{"default":[],"type":"array","items":{"$ref":"#/$defs/ChipItem"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"defaultValue":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}},"required":["name","type","items"],"additionalProperties":false,"description":"A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`."},"ChipItem":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"disabled":{"type":"boolean"}},"required":["value","label"],"additionalProperties":false,"description":"A single selectable chip inside a Chips group, with a value, label and optional icon."},"Icon":{"type":"object","properties":{"name":{"type":"string"},"category":{"type":"string"}},"required":["name"],"additionalProperties":false,"description":"A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve."},"OptionCards":{"type":"object","properties":{"name":{"type":"string"},"type":{"default":"single","type":"string","enum":["single","multiple"]},"items":{"default":[],"type":"array","items":{"$ref":"#/$defs/OptionCard"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"defaultValue":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}},"required":["name","type","items"],"additionalProperties":false,"description":"A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`."},"OptionCard":{"type":"object","properties":{"value":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"topContent":{"anyOf":[{"$ref":"#/$defs/Icon"},{"$ref":"#/$defs/Image"}]},"disabled":{"type":"boolean"}},"required":["value","title"],"additionalProperties":false,"description":"A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top."},"IconButton":{"type":"object","properties":{"name":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"variant":{"type":"string","enum":["primary","secondary","tertiary"]},"size":{"type":"string","enum":["extra-small","small","medium","large"]},"shape":{"type":"string","enum":["square","circle"]}},"required":["name","icon"],"additionalProperties":false,"description":"Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click."},"Steps":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/StepsItem"}}},"required":["items"],"additionalProperties":false,"description":"Step-by-step guide"},"StepsItem":{"type":"object","properties":{"title":{"type":"string"},"details":{"type":"string"}},"required":["title","details"],"additionalProperties":false,"description":"title and details text for one step"},"InlineHeader":{"type":"object","properties":{"heading":{"type":"string"},"description":{"type":"string"}},"required":["heading"],"additionalProperties":false,"description":"Compact section heading with an optional one-line description, for use inside cards."},"EntityList":{"type":"object","properties":{"rows":{"default":[],"type":"array","items":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false}},"size":{"default":"default","type":"string","enum":["small","default"]},"header":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false},"footer":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false}},"required":["rows","size"],"additionalProperties":false,"description":"Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers."},"EditableTable":{"type":"object","properties":{"name":{"default":"","type":"string"},"columns":{"default":[],"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["text","number","date-single","select","url"]},"key":{"default":"default","type":"string"},"header":{"default":"","type":"string"},"width":{"type":"number"},"options":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}},"required":["value","label"],"additionalProperties":false}}},"required":["type","key","header"],"additionalProperties":false}},"data":{"default":[],"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"values":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}}},"required":["id","values"],"additionalProperties":false}}},"required":["name","columns","data"],"additionalProperties":false,"description":"Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field"},"SnippetCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/SnippetCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action."},"SnippetCardItem":{"type":"object","properties":{"id":{"type":"string"},"lhs":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"}]},"rhs":{"anyOf":[{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/BoldText"}]}},"required":["lhs"],"additionalProperties":false,"description":"One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)."},"IconText":{"type":"object","properties":{"icon":{"$ref":"#/$defs/Icon"},"iconVariant":{"default":"neutral","type":"string","enum":["neutral","info","success","warning","danger","inverted","filled","soft"]},"iconSize":{"default":"m","type":"string","enum":["xs","s","m","l","xl","sm","md","lg"]},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"},"layout":{"default":"horizontal","type":"string","enum":["horizontal","vertical"]}},"required":["icon","iconVariant","iconSize","title","bold","layout"],"additionalProperties":false,"description":"An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color."},"ImageText":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"},"layout":{"default":"horizontal","type":"string","enum":["horizontal","vertical"]},"imageSize":{"type":"number"}},"required":["src","title","bold","layout"],"additionalProperties":false,"description":"A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL."},"Text":{"type":"object","properties":{"variant":{"default":"text","type":"string","enum":["text","number"]},"value":{"type":"string"},"subtext":{"type":"string"},"subtextVariant":{"default":"text","type":"string","enum":["text","number","metric"]},"size":{"default":"sm","type":"string","enum":["xs","sm","md","lg"]}},"required":["variant","value","subtextVariant","size"],"additionalProperties":false,"description":"Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"BoldText":{"type":"object","properties":{"variant":{"default":"text","type":"string","enum":["text","number"]},"value":{"type":"string"},"subtext":{"type":"string"},"subtextVariant":{"default":"text","type":"string","enum":["text","number","metric"]},"size":{"default":"sm","type":"string","enum":["xs","sm","md","lg"]}},"required":["variant","value","subtextVariant","size"],"additionalProperties":false,"description":"Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"OverviewCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/OverviewCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action."},"OverviewCardItem":{"type":"object","properties":{"id":{"type":"string"},"top":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"},{"$ref":"#/$defs/Text"}]},"bottom":{"$ref":"#/$defs/MetricIndicatorInline"}},"required":["top"],"additionalProperties":false,"description":"One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom."},"MetricIndicatorInline":{"type":"object","properties":{"value":{"type":"string"},"subtext":{"type":"string"},"trend":{"type":"object","properties":{"direction":{"type":"string","enum":["up","down"]},"value":{"type":"number"}},"required":["direction","value"],"additionalProperties":false}},"required":["value"],"additionalProperties":false,"description":"Headline metric value with an optional +/- percentage trend and subtext, all on one line."},"ContextCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/ContextCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable."},"ContextCardItem":{"type":"object","properties":{"id":{"type":"string"},"title":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/Tag"}]},"body":{"type":"string"},"bgColor":{"type":"string","enum":["gray"]},"bgImageSrc":{"type":"string"},"bgImageAlt":{"type":"string"}},"required":["title"],"additionalProperties":false,"description":"A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image."},"Tag":{"type":"object","properties":{"text":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"size":{"type":"string","enum":["sm","md","lg"]},"variant":{"type":"string","enum":["neutral","info","success","warning","danger"]}},"required":["text"],"additionalProperties":false,"description":"Styled tag/badge with optional Icon and variant"},"CompositeCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/CompositeCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable."},"CompositeCardItem":{"type":"object","properties":{"id":{"type":"string"},"header":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"},{"$ref":"#/$defs/ImageTextLarge"},{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/Image"}]},"body":{"default":[],"type":"array","items":{"anyOf":[{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/BoldText"},{"$ref":"#/$defs/MetricIndicatorInline"},{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/ListBlock"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/EntityList"}]}},"footer":{"type":"object","properties":{"price":{"anyOf":[{"$ref":"#/$defs/BoldText"},{"$ref":"#/$defs/MetricIndicatorWithStrikethrough"}]},"button":{"$ref":"#/$defs/Button"}},"additionalProperties":false}},"required":["body"],"additionalProperties":false,"description":"A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer."},"ImageTextLarge":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"}},"required":["src","title","bold"],"additionalProperties":false,"description":"A full-width banner image above a bold title and optional subtitle. src must be a real image URL."},"ListBlock":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/ListItem"}},"variant":{"type":"string","enum":["number","image"]},"size":{"type":"string","enum":["default","small"]}},"required":["items"],"additionalProperties":false,"description":"A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list."},"ListItem":{"type":"object","properties":{"title":{"type":"string"},"subtitle":{"type":"string"},"image":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"}},"required":["src","alt"],"additionalProperties":false},"actionLabel":{"type":"string"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]}},"required":["title"],"additionalProperties":false,"description":"Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable."},"MetricIndicatorWithStrikethrough":{"type":"object","properties":{"value":{"type":"string"},"subtext":{"type":"string"},"previousValue":{"type":"string"},"trend":{"type":"object","properties":{"direction":{"type":"string","enum":["up","down"]},"value":{"type":"number"}},"required":["direction","value"],"additionalProperties":false}},"required":["value"],"additionalProperties":false,"description":"Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below."},"VisualCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/VisualCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable."},"VisualCardItem":{"type":"object","properties":{"body":{"$ref":"#/$defs/BoldText"},"id":{"type":"string"},"bgImageSrc":{"type":"string"},"tag":{"$ref":"#/$defs/Tag"},"bgImageAlt":{"type":"string"}},"required":["body"],"additionalProperties":false,"description":"A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)."},"FollowUpBlock":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/FollowUpItem"}}},"required":["items"],"additionalProperties":false,"description":"List of clickable follow-up suggestions placed at the end of a response"},"FollowUpItem":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"],"additionalProperties":false,"description":"Clickable follow-up suggestion — when clicked, sends text as user message"},"SectionBlock":{"type":"object","properties":{"sections":{"type":"array","items":{"$ref":"#/$defs/SectionItem"}},"isFoldable":{"type":"boolean"}},"required":["sections"],"additionalProperties":false,"description":"Collapsible accordion sections. Auto-opens sections as they stream in. Use SectionItem for each section."},"SectionItem":{"type":"object","properties":{"value":{"type":"string"},"trigger":{"type":"string"},"content":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"},{"$ref":"#/$defs/ListBlock"},{"$ref":"#/$defs/FollowUpBlock"},{"$ref":"#/$defs/Tabs"},{"$ref":"#/$defs/Accordion"}]}}},"required":["value","trigger","content"],"additionalProperties":false,"description":"Section with a label and collapsible content — used inside SectionBlock"},"Tabs":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/TabItem"}}},"required":["items"],"additionalProperties":false,"description":"Tabbed container"},"TabItem":{"type":"object","properties":{"value":{"type":"string"},"trigger":{"type":"string"},"content":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"},{"$ref":"#/$defs/ListBlock"},{"$ref":"#/$defs/FollowUpBlock"},{"$ref":"#/$defs/Accordion"}]}}},"required":["value","trigger","content"],"additionalProperties":false,"description":"value is unique id, trigger is tab label, content is array of components"},"Accordion":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/AccordionItem"}}},"required":["items"],"additionalProperties":false,"description":"Collapsible sections"},"AccordionItem":{"type":"object","properties":{"value":{"type":"string"},"trigger":{"type":"string"},"content":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"},{"$ref":"#/$defs/ListBlock"},{"$ref":"#/$defs/FollowUpBlock"}]}}},"required":["value","trigger","content"],"additionalProperties":false,"description":"value is unique id, trigger is section title"},"Carousel":{"type":"object","properties":{"children":{"type":"array","items":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"},{"$ref":"#/$defs/ListBlock"},{"$ref":"#/$defs/FollowUpBlock"}]}}},"variant":{"type":"string","enum":["card","sunk"]}},"required":["children"],"additionalProperties":false,"description":"Horizontal scrollable carousel"},"Slice":{"type":"object","properties":{"category":{"type":"string"},"value":{"type":"number"}},"required":["category","value"],"additionalProperties":false,"description":"One slice with label and numeric value"},"Label":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"],"additionalProperties":false,"description":"Text label"},"SwitchGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/SwitchItem"}},"variant":{"type":"string","enum":["clear","card","sunk"]},"value":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"boolean"}}},"required":["name","items"],"additionalProperties":false,"description":"Group of switch toggles"},"SwitchItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"},"defaultChecked":{"type":"boolean"}},"required":["name"],"additionalProperties":false,"description":"Individual switch toggle"}}},"root":"Card","reactive":{"Callout":["visible"],"Input":["value"],"TextArea":["value"],"Select":["value"],"DatePicker":["value"],"Slider":["value"],"CheckBoxGroup":["value"],"RadioGroup":["value"],"SwitchGroup":["value"]}}, +"openui": {"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"Card":{"$ref":"#/$defs/Card"},"CardHeader":{"$ref":"#/$defs/CardHeader"},"TextContent":{"$ref":"#/$defs/TextContent"},"MarkDownRenderer":{"$ref":"#/$defs/MarkDownRenderer"},"Callout":{"$ref":"#/$defs/Callout"},"TextCallout":{"$ref":"#/$defs/TextCallout"},"Image":{"$ref":"#/$defs/Image"},"ImageBlock":{"$ref":"#/$defs/ImageBlock"},"ImageGallery":{"$ref":"#/$defs/ImageGallery"},"CodeBlock":{"$ref":"#/$defs/CodeBlock"},"InlineHeader":{"$ref":"#/$defs/InlineHeader"},"Table":{"$ref":"#/$defs/Table"},"Col":{"$ref":"#/$defs/Col"},"EditableTable":{"$ref":"#/$defs/EditableTable"},"BarChart":{"$ref":"#/$defs/BarChart"},"LineChart":{"$ref":"#/$defs/LineChart"},"AreaChart":{"$ref":"#/$defs/AreaChart"},"RadarChart":{"$ref":"#/$defs/RadarChart"},"HorizontalBarChart":{"$ref":"#/$defs/HorizontalBarChart"},"Series":{"$ref":"#/$defs/Series"},"PieChart":{"$ref":"#/$defs/PieChart"},"RadialChart":{"$ref":"#/$defs/RadialChart"},"SingleStackedBarChart":{"$ref":"#/$defs/SingleStackedBarChart"},"Slice":{"$ref":"#/$defs/Slice"},"ScatterChart":{"$ref":"#/$defs/ScatterChart"},"ScatterSeries":{"$ref":"#/$defs/ScatterSeries"},"Point":{"$ref":"#/$defs/Point"},"Form":{"$ref":"#/$defs/Form"},"FormControl":{"$ref":"#/$defs/FormControl"},"Label":{"$ref":"#/$defs/Label"},"Input":{"$ref":"#/$defs/Input"},"TextArea":{"$ref":"#/$defs/TextArea"},"Select":{"$ref":"#/$defs/Select"},"SelectItem":{"$ref":"#/$defs/SelectItem"},"DatePicker":{"$ref":"#/$defs/DatePicker"},"Slider":{"$ref":"#/$defs/Slider"},"CheckBoxGroup":{"$ref":"#/$defs/CheckBoxGroup"},"CheckBoxItem":{"$ref":"#/$defs/CheckBoxItem"},"RadioGroup":{"$ref":"#/$defs/RadioGroup"},"RadioItem":{"$ref":"#/$defs/RadioItem"},"SwitchGroup":{"$ref":"#/$defs/SwitchGroup"},"SwitchItem":{"$ref":"#/$defs/SwitchItem"},"ChipItem":{"$ref":"#/$defs/ChipItem"},"Chips":{"$ref":"#/$defs/Chips"},"OptionCard":{"$ref":"#/$defs/OptionCard"},"OptionCards":{"$ref":"#/$defs/OptionCards"},"Button":{"$ref":"#/$defs/Button"},"Buttons":{"$ref":"#/$defs/Buttons"},"IconButton":{"$ref":"#/$defs/IconButton"},"Stack":{"$ref":"#/$defs/Stack"},"Tabs":{"$ref":"#/$defs/Tabs"},"TabItem":{"$ref":"#/$defs/TabItem"},"Accordion":{"$ref":"#/$defs/Accordion"},"AccordionItem":{"$ref":"#/$defs/AccordionItem"},"Steps":{"$ref":"#/$defs/Steps"},"StepsItem":{"$ref":"#/$defs/StepsItem"},"Carousel":{"$ref":"#/$defs/Carousel"},"Separator":{"$ref":"#/$defs/Separator"},"TagBlock":{"$ref":"#/$defs/TagBlock"},"Tag":{"$ref":"#/$defs/Tag"},"Icon":{"$ref":"#/$defs/Icon"},"EntityList":{"$ref":"#/$defs/EntityList"},"ListBlock":{"$ref":"#/$defs/ListBlock"},"ListItem":{"$ref":"#/$defs/ListItem"},"Text":{"$ref":"#/$defs/Text"},"BoldText":{"$ref":"#/$defs/BoldText"},"IconText":{"$ref":"#/$defs/IconText"},"ImageText":{"$ref":"#/$defs/ImageText"},"ImageTextLarge":{"$ref":"#/$defs/ImageTextLarge"},"MetricIndicatorInline":{"$ref":"#/$defs/MetricIndicatorInline"},"MetricIndicatorWithStrikethrough":{"$ref":"#/$defs/MetricIndicatorWithStrikethrough"},"SnippetCardItem":{"$ref":"#/$defs/SnippetCardItem"},"SnippetCardBlock":{"$ref":"#/$defs/SnippetCardBlock"},"OverviewCardItem":{"$ref":"#/$defs/OverviewCardItem"},"OverviewCardBlock":{"$ref":"#/$defs/OverviewCardBlock"},"ContextCardItem":{"$ref":"#/$defs/ContextCardItem"},"ContextCardBlock":{"$ref":"#/$defs/ContextCardBlock"},"CompositeCardItem":{"$ref":"#/$defs/CompositeCardItem"},"CompositeCardBlock":{"$ref":"#/$defs/CompositeCardBlock"},"VisualCardItem":{"$ref":"#/$defs/VisualCardItem"},"VisualCardBlock":{"$ref":"#/$defs/VisualCardBlock"},"Modal":{"$ref":"#/$defs/Modal"}},"required":["Card","CardHeader","TextContent","MarkDownRenderer","Callout","TextCallout","Image","ImageBlock","ImageGallery","CodeBlock","InlineHeader","Table","Col","EditableTable","BarChart","LineChart","AreaChart","RadarChart","HorizontalBarChart","Series","PieChart","RadialChart","SingleStackedBarChart","Slice","ScatterChart","ScatterSeries","Point","Form","FormControl","Label","Input","TextArea","Select","SelectItem","DatePicker","Slider","CheckBoxGroup","CheckBoxItem","RadioGroup","RadioItem","SwitchGroup","SwitchItem","ChipItem","Chips","OptionCard","OptionCards","Button","Buttons","IconButton","Stack","Tabs","TabItem","Accordion","AccordionItem","Steps","StepsItem","Carousel","Separator","TagBlock","Tag","Icon","EntityList","ListBlock","ListItem","Text","BoldText","IconText","ImageText","ImageTextLarge","MetricIndicatorInline","MetricIndicatorWithStrikethrough","SnippetCardItem","SnippetCardBlock","OverviewCardItem","OverviewCardBlock","ContextCardItem","ContextCardBlock","CompositeCardItem","CompositeCardBlock","VisualCardItem","VisualCardBlock","Modal"],"additionalProperties":false,"$defs":{"Card":{"type":"object","properties":{"children":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"},{"$ref":"#/$defs/Tabs"},{"$ref":"#/$defs/Carousel"},{"$ref":"#/$defs/Stack"}]}},"variant":{"type":"string","enum":["card","sunk","clear"]},"direction":{"type":"string","enum":["row","column"]},"gap":{"type":"string","enum":["none","xs","s","m","l","xl","2xl"]},"align":{"type":"string","enum":["start","center","end","stretch","baseline"]},"justify":{"type":"string","enum":["start","center","end","between","around","evenly"]},"wrap":{"type":"boolean"}},"required":["children"],"additionalProperties":false,"description":"Styled container. variant: \"card\" (default, elevated) | \"sunk\" (recessed) | \"clear\" (transparent). Always full width. Accepts all Stack flex params (default: direction \"column\"). Cards flex to share space in row/wrap layouts."},"TextContent":{"type":"object","properties":{"text":{"type":"string"},"size":{"type":"string","enum":["small","default","large","small-heavy","large-heavy"]}},"required":["text"],"additionalProperties":false,"description":"Text block. Supports markdown. Optional size: \"small\" | \"default\" | \"large\" | \"small-heavy\" | \"large-heavy\"."},"MarkDownRenderer":{"type":"object","properties":{"textMarkdown":{"type":"string"},"variant":{"type":"string","enum":["clear","card","sunk"]}},"required":["textMarkdown"],"additionalProperties":false,"description":"Renders markdown text with optional container variant"},"CardHeader":{"type":"object","properties":{"title":{"type":"string"},"subtitle":{"type":"string"}},"additionalProperties":false,"description":"Header with optional title and subtitle"},"Callout":{"type":"object","properties":{"variant":{"type":"string","enum":["info","warning","error","success","neutral"]},"title":{"type":"string"},"description":{"type":"string"},"visible":{"type":"boolean"}},"required":["variant","title","description"],"additionalProperties":false,"description":"Callout banner. Optional visible is a reactive $boolean — auto-dismisses after 3s by setting $visible to false."},"TextCallout":{"type":"object","properties":{"variant":{"type":"string","enum":["neutral","info","warning","success","danger"]},"title":{"type":"string"},"description":{"type":"string"}},"additionalProperties":false,"description":"Text callout with variant, title, and description"},"CodeBlock":{"type":"object","properties":{"language":{"type":"string"},"codeString":{"type":"string"}},"required":["language","codeString"],"additionalProperties":false,"description":"Syntax-highlighted code block"},"Image":{"type":"object","properties":{"alt":{"type":"string"},"src":{"type":"string"}},"required":["alt"],"additionalProperties":false,"description":"Image with alt text and optional URL"},"ImageBlock":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"}},"required":["src"],"additionalProperties":false,"description":"Image block with loading state"},"ImageGallery":{"type":"object","properties":{"images":{"type":"array","items":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"details":{"type":"string"}},"required":["src"],"additionalProperties":false}}},"required":["images"],"additionalProperties":false,"description":"Gallery grid of images with modal preview"},"Separator":{"type":"object","properties":{"orientation":{"type":"string","enum":["horizontal","vertical"]},"decorative":{"type":"boolean"}},"additionalProperties":false,"description":"Visual divider between content sections"},"HorizontalBarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["grouped","stacked"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"}},"required":["labels","series"],"additionalProperties":false,"description":"Horizontal bars; prefer when category labels are long or for ranked lists"},"Series":{"type":"object","properties":{"category":{"type":"string"},"values":{"type":"array","items":{"type":"number"}}},"required":["category","values"],"additionalProperties":false,"description":"One data series"},"RadarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}}},"required":["labels","series"],"additionalProperties":false,"description":"Spider/web chart; use for comparing multiple variables across one or more entities"},"PieChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}},"variant":{"type":"string","enum":["pie","donut"]},"appearance":{"type":"string","enum":["circular","semiCircular"]}},"required":["labels","values"],"additionalProperties":false,"description":"Circular slices; use plucked arrays: PieChart(data.categories, data.values)"},"RadialChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}}},"required":["labels","values"],"additionalProperties":false,"description":"Radial bars; use plucked arrays: RadialChart(data.categories, data.values)"},"SingleStackedBarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}}},"required":["labels","values"],"additionalProperties":false,"description":"Single horizontal stacked bar; use plucked arrays: SingleStackedBarChart(data.categories, data.values)"},"ScatterChart":{"type":"object","properties":{"datasets":{"type":"array","items":{"$ref":"#/$defs/ScatterSeries"}},"xLabel":{"type":"string"},"yLabel":{"type":"string"}},"required":["datasets"],"additionalProperties":false,"description":"X/Y scatter plot; use for correlations, distributions, and clustering"},"ScatterSeries":{"type":"object","properties":{"name":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/$defs/Point"}}},"required":["name","points"],"additionalProperties":false,"description":"Named dataset"},"Point":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}},"required":["x","y"],"additionalProperties":false,"description":"Data point with numeric coordinates"},"AreaChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["linear","natural","step"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Filled area under lines; use for cumulative totals or volume trends over time"},"BarChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["grouped","stacked"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Vertical bars; use for comparing values across categories with one or more series"},"LineChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"series":{"type":"array","items":{"$ref":"#/$defs/Series"}},"variant":{"type":"string","enum":["linear","natural","step"]},"xLabel":{"type":"string"},"yLabel":{"type":"string"},"height":{"type":"number"}},"required":["labels","series"],"additionalProperties":false,"description":"Lines over categories; use for trends and continuous data over time"},"Table":{"type":"object","properties":{"columns":{"type":"array","items":{"$ref":"#/$defs/Col"}}},"required":["columns"],"additionalProperties":false,"description":"Data table — column-oriented. Each Col holds its own data array."},"Col":{"type":"object","properties":{"label":{"type":"string"},"data":{},"type":{"type":"string","enum":["string","number","action"]}},"required":["label","data"],"additionalProperties":false,"description":"Column definition — holds label + data array"},"TagBlock":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"}},"size":{"type":"string","enum":["sm","md","lg"]}},"required":["tags"],"additionalProperties":false,"description":"tags is an array of strings; optional size sm | md | lg"},"Form":{"type":"object","properties":{"name":{"type":"string"},"buttons":{"$ref":"#/$defs/Buttons"},"fields":{"default":[],"type":"array","items":{"$ref":"#/$defs/FormControl"}}},"required":["name","buttons","fields"],"additionalProperties":false,"description":"Form container with fields and explicit action buttons"},"Buttons":{"type":"object","properties":{"buttons":{"type":"array","items":{"$ref":"#/$defs/Button"}},"direction":{"type":"string","enum":["row","column"]}},"required":["buttons"],"additionalProperties":false,"description":"Group of Button components. direction: \"row\" (default) | \"column\"."},"Button":{"type":"object","properties":{"label":{"type":"string"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"variant":{"type":"string","enum":["primary","secondary","tertiary"]},"type":{"type":"string","enum":["normal","destructive"]},"size":{"type":"string","enum":["extra-small","small","medium","large"]}},"required":["label"],"additionalProperties":false,"description":"Clickable button"},"FormControl":{"type":"object","properties":{"label":{"type":"string"},"input":{"anyOf":[{"$ref":"#/$defs/Input"},{"$ref":"#/$defs/TextArea"},{"$ref":"#/$defs/Select"},{"$ref":"#/$defs/DatePicker"},{"$ref":"#/$defs/Slider"},{"$ref":"#/$defs/CheckBoxGroup"},{"$ref":"#/$defs/RadioGroup"},{"$ref":"#/$defs/Chips"},{"$ref":"#/$defs/OptionCards"}]},"hint":{"type":"string"}},"required":["label","input"],"additionalProperties":false,"description":"Field with label, input component, and optional hint text"},"Input":{"type":"object","properties":{"name":{"type":"string"},"placeholder":{"type":"string"},"type":{"type":"string","enum":["text","email","password","number","url"]},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name"],"additionalProperties":false},"TextArea":{"type":"object","properties":{"name":{"type":"string"},"placeholder":{"type":"string"},"rows":{"type":"number"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name"],"additionalProperties":false},"Select":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/SelectItem"}},"placeholder":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"},"size":{"type":"string","enum":["small","medium","large"]}},"required":["name","items"],"additionalProperties":false},"SelectItem":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}},"required":["value","label"],"additionalProperties":false,"description":"Option for Select"},"DatePicker":{"type":"object","properties":{"name":{"type":"string"},"mode":{"type":"string","enum":["single","range"]},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{}},"required":["name"],"additionalProperties":false},"Slider":{"type":"object","properties":{"name":{"type":"string"},"variant":{"type":"string","enum":["continuous","discrete"]},"min":{"type":"number"},"max":{"type":"number"},"step":{"type":"number"},"defaultValue":{"type":"array","items":{"type":"number"}},"label":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"array","items":{"type":"number"}}},"required":["name","variant","min","max"],"additionalProperties":false,"description":"Numeric slider input; supports continuous and discrete (stepped) variants"},"CheckBoxGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/CheckBoxItem"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"boolean"}}},"required":["name","items"],"additionalProperties":false},"CheckBoxItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"},"defaultChecked":{"type":"boolean"}},"required":["label","description","name"],"additionalProperties":false},"RadioGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/RadioItem"}},"defaultValue":{"type":"string"},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"value":{"type":"string"}},"required":["name","items"],"additionalProperties":false},"RadioItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"value":{"type":"string"}},"required":["label","description","value"],"additionalProperties":false},"Chips":{"type":"object","properties":{"name":{"type":"string"},"type":{"default":"multiple","type":"string","enum":["single","multiple"]},"items":{"default":[],"type":"array","items":{"$ref":"#/$defs/ChipItem"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"defaultValue":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}},"required":["name","type","items"],"additionalProperties":false,"description":"A form field of compact selectable chips for choosing one or many short options; the selection is stored under `name`."},"ChipItem":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"disabled":{"type":"boolean"}},"required":["value","label"],"additionalProperties":false,"description":"A single selectable chip inside a Chips group, with a value, label and optional icon."},"Icon":{"type":"object","properties":{"name":{"type":"string"},"category":{"type":"string"}},"required":["name"],"additionalProperties":false,"description":"A lucide icon by kebab-case name (e.g. 'circle-check'). Optional category picks a topical fallback when the name doesn't resolve."},"OptionCards":{"type":"object","properties":{"name":{"type":"string"},"type":{"default":"single","type":"string","enum":["single","multiple"]},"items":{"default":[],"type":"array","items":{"$ref":"#/$defs/OptionCard"}},"rules":{"type":"object","properties":{"required":{"type":"boolean"},"email":{"type":"boolean"},"url":{"type":"boolean"},"numeric":{"type":"boolean"},"min":{"type":"number"},"max":{"type":"number"},"minLength":{"type":"number"},"maxLength":{"type":"number"},"pattern":{"type":"string"}},"additionalProperties":false},"defaultValue":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}},"required":["name","type","items"],"additionalProperties":false,"description":"A form field of selectable cards (title, optional subtitle, optional icon or image) laid out in a responsive grid for choosing one or many options; the selection is stored under `name`."},"OptionCard":{"type":"object","properties":{"value":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"topContent":{"anyOf":[{"$ref":"#/$defs/Icon"},{"$ref":"#/$defs/Image"}]},"disabled":{"type":"boolean"}},"required":["value","title"],"additionalProperties":false,"description":"A single selectable card inside an OptionCards group, with a value, title, optional subtitle and an optional Icon or Image on top."},"IconButton":{"type":"object","properties":{"name":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"variant":{"type":"string","enum":["primary","secondary","tertiary"]},"size":{"type":"string","enum":["extra-small","small","medium","large"]},"shape":{"type":"string","enum":["square","circle"]}},"required":["name","icon"],"additionalProperties":false,"description":"Icon-only button. name is the accessible label and the action label; icon is an Icon; action fires on click."},"Steps":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/StepsItem"}}},"required":["items"],"additionalProperties":false,"description":"Step-by-step guide"},"StepsItem":{"type":"object","properties":{"title":{"type":"string"},"details":{"type":"string"}},"required":["title","details"],"additionalProperties":false,"description":"title and details text for one step"},"InlineHeader":{"type":"object","properties":{"heading":{"type":"string"},"description":{"type":"string"}},"required":["heading"],"additionalProperties":false,"description":"Compact section heading with an optional one-line description, for use inside cards."},"EntityList":{"type":"object","properties":{"rows":{"default":[],"type":"array","items":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false}},"size":{"default":"default","type":"string","enum":["small","default"]},"header":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false},"footer":{"type":"object","properties":{"left":{"type":"string"},"right":{"type":"string"},"rightVariant":{"default":"text","type":"string","enum":["text","number"]}},"required":["left","right","rightVariant"],"additionalProperties":false}},"required":["rows","size"],"additionalProperties":false,"description":"Two-column key/value rows (left label, right value). size 'default' supports optional header and footer rows; rightVariant 'number' uses tabular numbers."},"EditableTable":{"type":"object","properties":{"name":{"default":"","type":"string"},"columns":{"default":[],"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["text","number","date-single","select","url"]},"key":{"default":"default","type":"string"},"header":{"default":"","type":"string"},"width":{"type":"number"},"options":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}},"required":["value","label"],"additionalProperties":false}}},"required":["type","key","header"],"additionalProperties":false}},"data":{"default":[],"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"values":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}}},"required":["id","values"],"additionalProperties":false}}},"required":["name","columns","data"],"additionalProperties":false,"description":"Spreadsheet-like table whose cells the user can edit inline (text, number, url, date, select columns); edits are saved back as a form field"},"SnippetCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/SnippetCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A responsive grid of compact label/value cards (2 per row) for showing several short facts side by side; optionally clickable with a shared action."},"SnippetCardItem":{"type":"object","properties":{"id":{"type":"string"},"lhs":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"}]},"rhs":{"anyOf":[{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/BoldText"}]}},"required":["lhs"],"additionalProperties":false,"description":"One row-style snippet card: a label on the left (IconText or ImageText) and an optional value on the right (Text or BoldText)."},"IconText":{"type":"object","properties":{"icon":{"$ref":"#/$defs/Icon"},"iconVariant":{"default":"neutral","type":"string","enum":["neutral","info","success","warning","danger","inverted","filled","soft"]},"iconSize":{"default":"m","type":"string","enum":["xs","s","m","l","xl","sm","md","lg"]},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"},"layout":{"default":"horizontal","type":"string","enum":["horizontal","vertical"]}},"required":["icon","iconVariant","iconSize","title","bold","layout"],"additionalProperties":false,"description":"An icon badge with a title and optional subtitle, laid out horizontally or vertically. iconVariant sets the badge color."},"ImageText":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"},"layout":{"default":"horizontal","type":"string","enum":["horizontal","vertical"]},"imageSize":{"type":"number"}},"required":["src","title","bold","layout"],"additionalProperties":false,"description":"A small square image (thumbnail/avatar) with a title and optional subtitle. src must be a real image URL."},"Text":{"type":"object","properties":{"variant":{"default":"text","type":"string","enum":["text","number"]},"value":{"type":"string"},"subtext":{"type":"string"},"subtextVariant":{"default":"text","type":"string","enum":["text","number","metric"]},"size":{"default":"sm","type":"string","enum":["xs","sm","md","lg"]}},"required":["variant","value","subtextVariant","size"],"additionalProperties":false,"description":"Plain text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"BoldText":{"type":"object","properties":{"variant":{"default":"text","type":"string","enum":["text","number"]},"value":{"type":"string"},"subtext":{"type":"string"},"subtextVariant":{"default":"text","type":"string","enum":["text","number","metric"]},"size":{"default":"sm","type":"string","enum":["xs","sm","md","lg"]}},"required":["variant","value","subtextVariant","size"],"additionalProperties":false,"description":"Emphasized (bold) text line with optional subtext. variant 'number' uses tabular number styling; subtextVariant 'metric' colors a leading +/- subtext green/red."},"OverviewCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/OverviewCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or horizontal carousel of compact overview cards, each with a heading (icon/image/text) on top and an inline metric below; optionally clickable with a shared action."},"OverviewCardItem":{"type":"object","properties":{"id":{"type":"string"},"top":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"},{"$ref":"#/$defs/Text"}]},"bottom":{"$ref":"#/$defs/MetricIndicatorInline"}},"required":["top"],"additionalProperties":false,"description":"One overview card: a heading slot at the top (IconText, ImageText or Text) and an optional MetricIndicatorInline at the bottom."},"MetricIndicatorInline":{"type":"object","properties":{"value":{"type":"string"},"subtext":{"type":"string"},"trend":{"type":"object","properties":{"direction":{"type":"string","enum":["up","down"]},"value":{"type":"number"}},"required":["direction","value"],"additionalProperties":false}},"required":["value"],"additionalProperties":false,"description":"Headline metric value with an optional +/- percentage trend and subtext, all on one line."},"ContextCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/ContextCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or carousel of compact tinted context cards (title or tag plus a short bold body); an optional action makes every card clickable."},"ContextCardItem":{"type":"object","properties":{"id":{"type":"string"},"title":{"anyOf":[{"type":"string"},{"$ref":"#/$defs/Tag"}]},"body":{"type":"string"},"bgColor":{"type":"string","enum":["gray"]},"bgImageSrc":{"type":"string"},"bgImageAlt":{"type":"string"}},"required":["title"],"additionalProperties":false,"description":"A single card inside a ContextCardBlock: a title (plain string or Tag), an optional markdown body, and an optional gray tint or background image."},"Tag":{"type":"object","properties":{"text":{"type":"string"},"icon":{"$ref":"#/$defs/Icon"},"size":{"type":"string","enum":["sm","md","lg"]},"variant":{"type":"string","enum":["neutral","info","success","warning","danger"]}},"required":["text"],"additionalProperties":false,"description":"Styled tag/badge with optional Icon and variant"},"CompositeCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/CompositeCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A two-per-row grid or carousel of rich cards, each with an optional header, stacked body content (text, metrics, charts, lists, tags) and a price/button footer; an optional action makes every card clickable."},"CompositeCardItem":{"type":"object","properties":{"id":{"type":"string"},"header":{"anyOf":[{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/ImageText"},{"$ref":"#/$defs/ImageTextLarge"},{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/Image"}]},"body":{"default":[],"type":"array","items":{"anyOf":[{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/BoldText"},{"$ref":"#/$defs/MetricIndicatorInline"},{"$ref":"#/$defs/IconText"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/ListBlock"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/EntityList"}]}},"footer":{"type":"object","properties":{"price":{"anyOf":[{"$ref":"#/$defs/BoldText"},{"$ref":"#/$defs/MetricIndicatorWithStrikethrough"}]},"button":{"$ref":"#/$defs/Button"}},"additionalProperties":false}},"required":["body"],"additionalProperties":false,"description":"A single card inside a CompositeCardBlock: an optional header (icon/image/text), a stack of body elements (text, metrics, charts, lists, tags), and an optional price/button footer."},"ImageTextLarge":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"bold":{"default":false,"type":"boolean"}},"required":["src","title","bold"],"additionalProperties":false,"description":"A full-width banner image above a bold title and optional subtitle. src must be a real image URL."},"ListBlock":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/ListItem"}},"variant":{"type":"string","enum":["number","image"]},"size":{"type":"string","enum":["default","small"]}},"required":["items"],"additionalProperties":false,"description":"A list of items with number or image indicators. Each item can optionally have an action. size small renders a compact list."},"ListItem":{"type":"object","properties":{"title":{"type":"string"},"subtitle":{"type":"string"},"image":{"type":"object","properties":{"src":{"type":"string"},"alt":{"type":"string"}},"required":["src","alt"],"additionalProperties":false},"actionLabel":{"type":"string"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]}},"required":["title"],"additionalProperties":false,"description":"Item in a ListBlock — displays a title with an optional subtitle and image. When action is provided, the item becomes clickable."},"MetricIndicatorWithStrikethrough":{"type":"object","properties":{"value":{"type":"string"},"subtext":{"type":"string"},"previousValue":{"type":"string"},"trend":{"type":"object","properties":{"direction":{"type":"string","enum":["up","down"]},"value":{"type":"number"}},"required":["direction","value"],"additionalProperties":false}},"required":["value"],"additionalProperties":false,"description":"Headline metric value with an optional struck-through previousValue, a +/- percentage trend, and subtext below."},"VisualCardBlock":{"type":"object","properties":{"items":{"minItems":2,"type":"array","items":{"$ref":"#/$defs/VisualCardItem"}},"layout":{"default":"grid","type":"string","enum":["grid","carousel"]},"responsive":{"default":true,"type":"boolean"},"action":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string"}},"required":["type","url"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"continue_conversation"},"context":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string"},"params":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"],"additionalProperties":false}]},"gap":{"anyOf":[{"type":"number"},{"type":"string"}]}},"required":["items","layout","responsive"],"additionalProperties":false,"description":"A grid or carousel of photo-first cards: a full-bleed background image with a tag on top and a bold text panel at the bottom; an optional action makes every card clickable."},"VisualCardItem":{"type":"object","properties":{"body":{"$ref":"#/$defs/BoldText"},"id":{"type":"string"},"bgImageSrc":{"type":"string"},"tag":{"$ref":"#/$defs/Tag"},"bgImageAlt":{"type":"string"}},"required":["body"],"additionalProperties":false,"description":"A single photo-first card inside a VisualCardBlock: a BoldText body panel, an optional Tag, and a background image (bgImageSrc must be a real URL; bgImageAlt is its alt text)."},"Tabs":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/TabItem"}}},"required":["items"],"additionalProperties":false,"description":"Tabbed container"},"TabItem":{"type":"object","properties":{"value":{"type":"string"},"trigger":{"type":"string"},"content":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}}},"required":["value","trigger","content"],"additionalProperties":false,"description":"value is unique id, trigger is tab label, content is array of components"},"Carousel":{"type":"object","properties":{"children":{"type":"array","items":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}}},"variant":{"type":"string","enum":["card","sunk"]}},"required":["children"],"additionalProperties":false,"description":"Horizontal scrollable carousel"},"Stack":{"type":"object","properties":{"children":{"type":"array","items":{}},"direction":{"type":"string","enum":["row","column"]},"gap":{"type":"string","enum":["none","xs","s","m","l","xl","2xl"]},"align":{"type":"string","enum":["start","center","end","stretch","baseline"]},"justify":{"type":"string","enum":["start","center","end","between","around","evenly"]},"wrap":{"type":"boolean"}},"required":["children"],"additionalProperties":false,"description":"Flex container. direction: \"row\"|\"column\" (default \"column\"). gap: \"none\"|\"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"2xl\" (default \"m\"). align: \"start\"|\"center\"|\"end\"|\"stretch\"|\"baseline\". justify: \"start\"|\"center\"|\"end\"|\"between\"|\"around\"|\"evenly\"."},"Slice":{"type":"object","properties":{"category":{"type":"string"},"value":{"type":"number"}},"required":["category","value"],"additionalProperties":false,"description":"One slice with label and numeric value"},"Label":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"],"additionalProperties":false,"description":"Text label"},"SwitchGroup":{"type":"object","properties":{"name":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/$defs/SwitchItem"}},"variant":{"type":"string","enum":["clear","card","sunk"]},"value":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"boolean"}}},"required":["name","items"],"additionalProperties":false,"description":"Group of switch toggles"},"SwitchItem":{"type":"object","properties":{"label":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"},"defaultChecked":{"type":"boolean"}},"required":["name"],"additionalProperties":false,"description":"Individual switch toggle"},"Accordion":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/$defs/AccordionItem"}}},"required":["items"],"additionalProperties":false,"description":"Collapsible sections"},"AccordionItem":{"type":"object","properties":{"value":{"type":"string"},"trigger":{"type":"string"},"content":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}}},"required":["value","trigger","content"],"additionalProperties":false,"description":"value is unique id, trigger is section title"},"Modal":{"type":"object","properties":{"title":{"type":"string"},"open":{"type":"boolean"},"children":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/TextContent"},{"$ref":"#/$defs/MarkDownRenderer"},{"$ref":"#/$defs/CardHeader"},{"$ref":"#/$defs/Callout"},{"$ref":"#/$defs/TextCallout"},{"$ref":"#/$defs/CodeBlock"},{"$ref":"#/$defs/Image"},{"$ref":"#/$defs/ImageBlock"},{"$ref":"#/$defs/ImageGallery"},{"$ref":"#/$defs/Separator"},{"$ref":"#/$defs/HorizontalBarChart"},{"$ref":"#/$defs/RadarChart"},{"$ref":"#/$defs/PieChart"},{"$ref":"#/$defs/RadialChart"},{"$ref":"#/$defs/SingleStackedBarChart"},{"$ref":"#/$defs/ScatterChart"},{"$ref":"#/$defs/AreaChart"},{"$ref":"#/$defs/BarChart"},{"$ref":"#/$defs/LineChart"},{"$ref":"#/$defs/Table"},{"$ref":"#/$defs/TagBlock"},{"$ref":"#/$defs/Form"},{"$ref":"#/$defs/Buttons"},{"$ref":"#/$defs/IconButton"},{"$ref":"#/$defs/Steps"},{"$ref":"#/$defs/InlineHeader"},{"$ref":"#/$defs/EntityList"},{"$ref":"#/$defs/EditableTable"},{"$ref":"#/$defs/SnippetCardBlock"},{"$ref":"#/$defs/OverviewCardBlock"},{"$ref":"#/$defs/ContextCardBlock"},{"$ref":"#/$defs/CompositeCardBlock"},{"$ref":"#/$defs/VisualCardBlock"}]}},"size":{"type":"string","enum":["sm","md","lg"]}},"required":["title","children"],"additionalProperties":false,"description":"Modal dialog. open is a reactive $boolean binding — set to true to open, X/Escape/backdrop auto-closes. Put Form with buttons inside children."}}},"root":"Stack","reactive":{"Callout":["visible"],"Input":["value"],"TextArea":["value"],"Select":["value"],"DatePicker":["value"],"Slider":["value"],"CheckBoxGroup":["value"],"RadioGroup":["value"],"SwitchGroup":["value"],"Modal":["open"]}}, +"test": {"schema":{"$defs":{"Card":{"properties":{"children":{"type":"array","items":{"anyOf":[{"$ref":"#/$defs/Text"},{"$ref":"#/$defs/Button"},{"$ref":"#/$defs/Chart"}]}},"title":{"type":"string"}},"required":["children"]},"Text":{"properties":{"text":{"type":"string"},"size":{"type":"string","enum":["s","m","l"],"default":"m"}},"required":["text"]},"Button":{"properties":{"label":{"type":"string"},"action":{},"variant":{"type":"string","enum":["primary","secondary"]}},"required":["label"]},"Input":{"properties":{"name":{"type":"string"},"value":{"type":"string"}},"required":["name"]},"Chart":{"properties":{"labels":{"type":"array","items":{"type":"string"}},"values":{"type":"array","items":{"type":"number"}},"meta":{"type":"object","properties":{"unit":{"type":"string"},"scale":{"type":"number","default":1}},"required":["unit"]}},"required":["labels","values"]},"Tagged":{"properties":{"count":{"type":"integer"},"flag":{"type":"boolean"},"kind":{"const":"x"},"tone":{"type":"string","default":"neutral"}},"required":["tone"]}}},"root":"Card","reactive":{"Input":["value"]}}, +"hoisted": {"schema":{"properties":{"Tree":{}},"$defs":{"Tree":{"properties":{"node":{"$ref":"#/$defs/__schema0"}},"required":["node"]},"__schema0":{"type":"object","properties":{"label":{"type":"string"}}}}},"root":"Tree","reactive":{}} } diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/stream-set.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/stream-set.json index 308ecef7bd..d938569352 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/stream-set.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/stream-set.json @@ -1,669 +1,8 @@ [ - { - "name": "basic", - "schema": "test", - "steps": [ - { - "text": "root = Card([t1, b1])\nt1 = ", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [ - "t1", - "b1" - ], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "text": "root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "Hi" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "t1" - }, - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Go" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "b1" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 3, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "text": "root = Card([Text(\"replaced\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "replaced" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - } - ] - }, - { - "name": "missing-required", - "schema": "test", - "steps": [ - { - "text": "root = Card([t1, b1])\nt1 ", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [ - "t1", - "b1" - ], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "text": "root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Button", - "props": { - "label": "Go" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "b1" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 3, - "errors": [ - { - "code": "missing-required", - "component": "Text", - "path": "/text", - "message": "missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")", - "statementId": "t1" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "text": "root = Card([Text(\"replaced\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "replaced" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - } - ] - }, - { - "name": "null-required-with-default", - "schema": "test", - "steps": [ - { - "text": "root = Card([t1]", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [] - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": true, - "unresolved": [ - "t1" - ], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "text": "root = Card([t1])\nt1 = Text(null)", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [ - { - "code": "null-required", - "component": "Text", - "path": "/text", - "message": "required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")", - "statementId": "t1" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "text": "root = Card([Text(\"replaced\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "replaced" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - } - ] - }, - { - "name": "required-default-fills", - "schema": "test", - "steps": [ - { - "text": "root = Card([x])\nx = Ta", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [ - "Ta" - ], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "text": "root = Card([x])\nx = Tagged(1, true, \"x\", null)", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Tagged", - "props": { - "count": 1, - "flag": true, - "kind": "x", - "tone": "neutral" - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "x" - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 2, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "text": "root = Card([Text(\"replaced\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "replaced" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - } - ] - }, - { - "name": "unknown-component", - "schema": "test", - "steps": [ - { - "text": "root = Card([Myster", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [] - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": true, - "unresolved": [ - "Myster" - ], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "text": "root = Card([Mystery(\"a\"), Text(\"b\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "b" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [ - { - "code": "unknown-component", - "component": "Mystery", - "path": "", - "message": "Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged", - "statementId": "root" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "text": "root = Card([Text(\"replaced\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "replaced" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - } - ] - }, - { - "name": "excess-args", - "schema": "test", - "steps": [ - { - "text": "root = Card([Text(\"a", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "a" - }, - "partial": true, - "hasDynamicProps": false - } - ] - }, - "partial": true, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": true, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "text": "root = Card([Text(\"a\", \"m\", \"extra\", 4)])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "a", - "size": "m" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [ - { - "code": "excess-args", - "component": "Text", - "path": "", - "message": "Text takes 2 arg(s), got 4 (2 excess dropped)", - "statementId": "root" - } - ] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - }, - { - "text": "root = Card([Text(\"replaced\")])", - "expected": { - "root": { - "type": "element", - "typeName": "Card", - "props": { - "children": [ - { - "type": "element", - "typeName": "Text", - "props": { - "text": "replaced" - }, - "partial": false, - "hasDynamicProps": false - } - ] - }, - "partial": false, - "hasDynamicProps": false, - "statementId": "root" - }, - "meta": { - "incomplete": false, - "unresolved": [], - "orphaned": [], - "statementCount": 1, - "errors": [] - }, - "stateDeclarations": {}, - "queryStatements": [], - "mutationStatements": [] - } - } - ] - } +{"name":"basic","schema":"test","steps":[{"text":"root = Card([t1, b1])\nt1 = ","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"text":"root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"text":"root = Card([Text(\"replaced\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"replaced"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"missing-required","schema":"test","steps":[{"text":"root = Card([t1, b1])\nt1 ","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"text":"root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"text":"root = Card([Text(\"replaced\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"replaced"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"null-required-with-default","schema":"test","steps":[{"text":"root = Card([t1]","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"text":"root = Card([t1])\nt1 = Text(null)","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"text":"root = Card([Text(\"replaced\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"replaced"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"required-default-fills","schema":"test","steps":[{"text":"root = Card([x])\nx = Ta","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Ta"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"text":"root = Card([x])\nx = Tagged(1, true, \"x\", null)","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"text":"root = Card([Text(\"replaced\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"replaced"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"unknown-component","schema":"test","steps":[{"text":"root = Card([Myster","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Myster"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"text":"root = Card([Mystery(\"a\"), Text(\"b\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"text":"root = Card([Text(\"replaced\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"replaced"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"excess-args","schema":"test","steps":[{"text":"root = Card([Text(\"a","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"text":"root = Card([Text(\"a\", \"m\", \"extra\", 4)])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"text":"root = Card([Text(\"replaced\")])","expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"replaced"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]} ] diff --git a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json index ede91f8860..3d562323e5 100644 --- a/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json +++ b/packages/swift-lang/Tests/OpenUILangTests/Fixtures/streaming.json @@ -1 +1,66 @@ -[{"name":"chat-example-1","schema":"chat","input":"Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }","checkpoints":[{"at":607,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["highlights","statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1214,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1821,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","valu":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ov2","ov3","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":13,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2428,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[],"isFoldable":null},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secLandmarks","secFood","secWhen","f","actionBtns","src1","src2"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3035,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":null,"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["lm1tagIcon","lm2","lm3","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3642,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["lm3body","lm3tag","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":33,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"lm3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["foodCards","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4856,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Sh"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":45,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5463,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"P"},"partial":true,"hasDynamicProps":false,"statementId":"sp2"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sp3","tabSummer","actionBtns","src1","src2"],"orphaned":[],"statementCount":51,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6070,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Sein"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["su2","su3","actionBtns","src1","src2"],"orphaned":[],"statementCount":55,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6677,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":true,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":true,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{}},"partial":true,"hasDynamicProps":false,"statementId":"btn2"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btn3","src1","src2"],"orphaned":[],"statementCount":60,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7277,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":false,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"springList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":false,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":false,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":false,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":false,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{"type":"continue_conversation","context":"Show me the best hotels in Paris"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn2"},{"type":"element","typeName":"Button","props":{"label":"Build a Paris Itinerary","action":{"type":"continue_conversation","context":"Build a 5-day Paris itinerary for me"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn3"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[{"title":"Paris Travel Guide 2025","sourceName":"Travel and Tour World","url":"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/"},{"title":"Best Things to Do in Paris 2026","sourceName":"Time Out Paris","url":"http://www.timeout.fr/paris/en/for-tourists"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-2","schema":"chat","input":"Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")","checkpoints":[{"at":510,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpi1icon","kpi1rhs","kpi2","kpi3","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi1lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1020,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3icon","kpi3rhs","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":13,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi3lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1530,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabGrowth","t","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2040,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["retentio","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2550,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":35,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3060,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tab","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3570,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Sta"]},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":47,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4080,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":null,"body":[]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["supportIcon","supportMetric","supportChart","supportList","cardMarketing","actionButtons"],"orphaned":[],"statementCount":51,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"supportHeader"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4590,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","rig":null}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sup2","sup3","cardMarketing","actionButtons"],"orphaned":[],"statementCount":58,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["marketingMetric","marketingChart","marketingList","actionButtons"],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":true,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":true,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":true,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":true,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Co"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["mkt3","actionButtons"],"orphaned":[],"statementCount":70,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6118,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":false,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":false,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":false,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":false,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Cost per Lead","right":"$48.20","rightVariant":"number"},{"left":"Top Channel","right":"Organic Search","rightVariant":"text"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Break Down by Channel","action":{"type":"continue_conversation","context":"Break down this month's revenue by acquisition channel"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnChannels"},{"type":"element","typeName":"Button","props":{"label":"Forecast Next Quarter","action":{"type":"continue_conversation","context":"Forecast revenue and active users for next quarter"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnForecast"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionButtons"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":74,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-3","schema":"chat","input":"Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)","checkpoints":[{"at":361,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas"},"partial":true,"hasDynamicProps":false,"statementId":"header"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","inspoCards","form"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":722,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["i","insp2","form"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"insp1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1083,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2","form"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1444,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":null,"size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2icon","form"],"orphaned":[],"statementCount":11,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1805,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btnSkip","fcDestination","fcDates","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":15,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2166,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Fo","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":19,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2527,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tr1","tr2","tr3","tr4","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2888,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["oc2","oc3","oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":29,"errors":[{"code":"missing-required","component":"OptionCard","path":"/title","message":"missing required field \"/title\" — signature: OptionCard(value*: string, title*: string, subtitle: string, topContent, disabled: boolean)","statementId":"oc1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":34,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fcNotes"],"orphaned":[],"statementCount":39,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"fcStay"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3971,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":null},"partial":true,"hasDynamicProps":false,"statementId":"ch3"}],"rules":{},"defaultValue":["hotel"]},"partial":true,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":true,"hasDynamicProps":false,"statementId":"fcStay"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ch4","fcNotes"],"orphaned":[],"statementCount":46,"errors":[{"code":"missing-required","component":"Icon","path":"/name","message":"missing required field \"/name\" — signature: Icon(name*: string, category: string)","statementId":"ch3icon"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4322,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":false,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":false,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":{"type":"element","typeName":"Icon","props":{"name":"home","category":"home"},"partial":false,"hasDynamicProps":false,"statementId":"ch3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch3"},{"type":"element","typeName":"ChipItem","props":{"value":"camping","label":"Camping / Glamping","icon":{"type":"element","typeName":"Icon","props":{"name":"tent","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"ch4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch4"}],"rules":{},"defaultValue":["hotel"]},"partial":false,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fcStay"},{"type":"element","typeName":"FormControl","props":{"label":"Special Requests or Notes","input":{"type":"element","typeName":"TextArea","props":{"name":"special-requests","placeholder":"e.g. vegetarian meals, wheelchair access, honeymoon surprise...","rows":4},"partial":false,"hasDynamicProps":false,"statementId":"notesArea"},"hint":"Any dietary needs, accessibility requirements, or specific interests?"},"partial":false,"hasDynamicProps":false,"statementId":"fcNotes"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":50,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-4","schema":"chat","input":"Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }","checkpoints":[{"at":218,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Ene"},"partial":true,"hasDynamicProps":false,"statementId":"header"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":436,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to w"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":654,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["v1body","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"v1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":872,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":null,"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v1icon","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1090,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":null,"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v2tag","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1308,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["CompositeCard","src1","src2"],"orphaned":[],"statementCount":14,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1526,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1icon","t1body","t1tags","t1btn","t2","src1","src2"],"orphaned":[],"statementCount":16,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t1h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1744,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Wa"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2","src1","src2"],"orphaned":[],"statementCount":20,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1962,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2icon","t2body","t2tags","t2btn","src1","src2"],"orphaned":[],"statementCount":22,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t2h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":[]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2btn","src1","src2"],"orphaned":[],"statementCount":25,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2398,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceN":null}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2615,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":false,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":false,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},{"title":"Sajan Re (Official Music Video)","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=COUSCnFazzc"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"chat-example-5","schema":"chat","input":"Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")","checkpoints":[{"at":37,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":74,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["title","tbl","followUps"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":111,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":""},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tbl","followUps"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":148,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":185,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs","users","followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":222,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Pyth"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years","followUps"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":259,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["years","followUps"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":296,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":333,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu1"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":370,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me m"},"partial":true,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu2"],"orphaned":[],"statementCount":8,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":407,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["FollowUpItem"],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":442,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"},{"type":"element","typeName":"FollowUpItem","props":{"text":"Show me a JavaScript comparison"},"partial":false,"hasDynamicProps":false,"statementId":"fu2"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"openui-example-1","schema":"openui","input":"Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]","checkpoints":[{"at":28,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["titl"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["TextContent","tbl"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":112,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-hea"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tbl"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":140,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":168,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":196,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs","users","years"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":224,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","Java"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":252,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":280,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript","Go"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["years"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":308,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript","Go"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1,8.5,5.2]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":336,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript","Go"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1,8.5,5.2]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995,2012,2009]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"openui-example-2","schema":"openui","input":"Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])","checkpoints":[{"at":22,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["title"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["TextC","chart"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":88,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":""},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["chart"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":110,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["chart"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["labels","s1"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"BarChart","path":"/labels","message":"required field \"/labels\" cannot be null — signature: BarChart(labels*: array, series*: array, variant: \"grouped\"|\"stacked\", xLabel: string, yLabel: string, height: number)","statementId":"chart"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":154,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["labels","s1","s2"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"BarChart","path":"/labels","message":"required field \"/labels\" cannot be null — signature: BarChart(labels*: array, series*: array, variant: \"grouped\"|\"stacked\", xLabel: string, yLabel: string, height: number)","statementId":"chart"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":176,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[],"variant":"grouped"},"partial":true,"hasDynamicProps":false,"statementId":"chart"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["s1","s2"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":198,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[],"variant":"grouped"},"partial":true,"hasDynamicProps":false,"statementId":"chart"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["s2"],"orphaned":[],"statementCount":5,"errors":[{"code":"missing-required","component":"Series","path":"/values","message":"missing required field \"/values\" — signature: Series(category*: string, values*: array)","statementId":"s1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":220,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[{"type":"element","typeName":"Series","props":{"category":"Product A","values":[120,150,180]},"partial":false,"hasDynamicProps":false,"statementId":"s1"}],"variant":"grouped"},"partial":false,"hasDynamicProps":false,"statementId":"chart"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["s2"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":242,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[{"type":"element","typeName":"Series","props":{"category":"Product A","values":[120,150,180]},"partial":true,"hasDynamicProps":false,"statementId":"s1"}],"variant":"grouped"},"partial":true,"hasDynamicProps":false,"statementId":"chart"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[{"code":"missing-required","component":"Series","path":"/values","message":"missing required field \"/values\" — signature: Series(category*: string, values*: array)","statementId":"s2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":261,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[{"type":"element","typeName":"Series","props":{"category":"Product A","values":[120,150,180]},"partial":false,"hasDynamicProps":false,"statementId":"s1"},{"type":"element","typeName":"Series","props":{"category":"Product B","values":[90,110,140]},"partial":false,"hasDynamicProps":false,"statementId":"s2"}],"variant":"grouped"},"partial":false,"hasDynamicProps":false,"statementId":"chart"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"openui-example-3","schema":"openui","input":"Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])","checkpoints":[{"at":74,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","form"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":148,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","nameFi"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":222,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","emailField","countryField","msgField"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"nameField"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":296,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btns","emailField","countryField","msgField"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":370,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","countryField","msgField"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":444,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","Sel","msgField"],"orphaned":[],"statementCount":6,"errors":[{"code":"null-required","component":"FormControl","path":"/input","message":"required field \"/input\" cannot be null — signature: FormControl(label*: string, input*, hint: string)","statementId":"countryField"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":518,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btns","countryOpts","F"],"orphaned":[],"statementCount":7,"errors":[{"code":"null-required","component":"Select","path":"/items","message":"required field \"/items\" cannot be null — signature: Select(name*: string, items*: array, placeholder: string, rules: object, value: string, size: \"small\"|\"medium\"|\"large\")","statementId":"countryField"},{"code":"null-required","component":"FormControl","path":"/input","message":"required field \"/input\" cannot be null — signature: FormControl(label*: string, input*, hint: string)","statementId":"countryField"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":592,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","countryOpts"],"orphaned":[],"statementCount":7,"errors":[{"code":"null-required","component":"Select","path":"/items","message":"required field \"/items\" cannot be null — signature: Select(name*: string, items*: array, placeholder: string, rules: object, value: string, size: \"small\"|\"medium\"|\"large\")","statementId":"countryField"},{"code":"null-required","component":"FormControl","path":"/input","message":"required field \"/input\" cannot be null — signature: FormControl(label*: string, input*, hint: string)","statementId":"countryField"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":666,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns"],"orphaned":[],"statementCount":8,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":740,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btns"],"orphaned":[],"statementCount":8,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":814,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Form","props":{"name":"contact","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Submit","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Submit"}]}]}]},"variant":"primary"},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"btns"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Name","input":{"type":"element","typeName":"Input","props":{"name":"name","placeholder":"Your name","type":"text","rules":{"required":true,"minLength":2}},"partial":true,"hasDynamicProps":false}},"partial":true,"hasDynamicProps":false,"statementId":"nameField"},{"type":"element","typeName":"FormControl","props":{"label":"Email","input":{"type":"element","typeName":"Input","props":{"name":"email","placeholder":"you@example.com","type":"email","rules":{"required":true,"email":true}},"partial":true,"hasDynamicProps":false}},"partial":true,"hasDynamicProps":false,"statementId":"emailField"},{"type":"element","typeName":"FormControl","props":{"label":"Country","input":{"type":"element","typeName":"Select","props":{"name":"country","items":[{"type":"element","typeName":"SelectItem","props":{"value":"us","label":"United States"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"uk","label":"United Kingdom"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"de","label":"Germany"},"partial":true,"hasDynamicProps":false}],"placeholder":"Select...","rules":{"required":true}},"partial":true,"hasDynamicProps":false}},"partial":true,"hasDynamicProps":false,"statementId":"countryField"},{"type":"element","typeName":"FormControl","props":{"label":"Message","input":{"type":"element","typeName":"TextArea","props":{"name":"message","placeholder":"Tell us more...","rows":4,"rules":{"required":true,"minLength":10}},"partial":true,"hasDynamicProps":false}},"partial":true,"hasDynamicProps":false,"statementId":"msgField"}]},"partial":true,"hasDynamicProps":true,"statementId":"form"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Bu"],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":877,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Form","props":{"name":"contact","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Submit","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Submit"}]}]}]},"variant":"primary"},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Cancel","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Cancel"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"btns"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Name","input":{"type":"element","typeName":"Input","props":{"name":"name","placeholder":"Your name","type":"text","rules":{"required":true,"minLength":2}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"nameField"},{"type":"element","typeName":"FormControl","props":{"label":"Email","input":{"type":"element","typeName":"Input","props":{"name":"email","placeholder":"you@example.com","type":"email","rules":{"required":true,"email":true}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"emailField"},{"type":"element","typeName":"FormControl","props":{"label":"Country","input":{"type":"element","typeName":"Select","props":{"name":"country","items":[{"type":"element","typeName":"SelectItem","props":{"value":"us","label":"United States"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"uk","label":"United Kingdom"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"de","label":"Germany"},"partial":false,"hasDynamicProps":false}],"placeholder":"Select...","rules":{"required":true}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"countryField"},{"type":"element","typeName":"FormControl","props":{"label":"Message","input":{"type":"element","typeName":"TextArea","props":{"name":"message","placeholder":"Tell us more...","rows":4,"rules":{"required":true,"minLength":10}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"msgField"}]},"partial":false,"hasDynamicProps":true,"statementId":"form"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"openui-example-4","schema":"openui","input":"Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]","checkpoints":[{"at":43,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":86,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabs"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"TextContent","path":"/text","message":"missing required field \"/text\" — signature: TextContent(text*: string, size: \"small\"|\"default\"|\"large\"|\"small-heavy\"|\"large-heavy\")","statementId":"title"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":129,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Tabs","path":"/items","message":"missing required field \"/items\" — signature: Tabs(items*: array)","statementId":"tabs"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":172,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabVue"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"TabItem","path":"/trigger","message":"missing required field \"/trigger\" — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabReact"},{"code":"missing-required","component":"TabItem","path":"/content","message":"missing required field \"/content\" — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabReact"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":215,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["reactContent","TabIte"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabReact"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":258,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["reactContent","vueContent"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabReact"},{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabVue"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":301,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta fo"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["vueContent"],"orphaned":[],"statementCount":6,"errors":[{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabVue"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":344,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["vueContent"],"orphaned":[],"statementCount":6,"errors":[{"code":"missing-required","component":"Callout","path":"/description","message":"missing required field \"/description\" — signature: Callout(variant*: \"info\"|\"warning\"|\"error\"|\"success\"|\"neutral\", title*: string, description*: string, visible: boolean)","statementId":"reactContent"},{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabVue"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":387,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":430,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[{"type":"element","typeName":"TextContent","props":{"text":"Vue is a progressive framework b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":473,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[{"type":"element","typeName":"TextContent","props":{"text":"Vue is a progressive framework by Evan You."},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"success","title":"Tip","description":"V"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":507,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[{"type":"element","typeName":"TextContent","props":{"text":"Vue is a progressive framework by Evan You."},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"success","title":"Tip","description":"Vue has a gentle learning curve."},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"openui-example-5","schema":"openui","input":"Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")","checkpoints":[{"at":164,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpiBlock","productsHeader","productCards"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":328,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi1icon","kpi1rhs","kpi2","kpi3","productsHeader","productCards"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi1lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":492,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3","productsHeader","productCards"],"orphaned":[],"statementCount":8,"errors":[{"code":"missing-required","component":"SnippetCardItem","path":"/lhs","message":"missing required field \"/lhs\" — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":656,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":null},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpi2rhs","kpi3","productsHeader","productCards"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":820,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3icon","kpi3rhs","productsHeader","productCards"],"orphaned":[],"statementCount":13,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi3lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":984,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Pro"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["productCards"],"orphaned":[],"statementCount":16,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1148,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":null,"body":[],"footer":null},"partial":true,"hasDynamicProps":false,"statementId":"p1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"productCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["p1icon","p1body","p1footer","p2"],"orphaned":[],"statementCount":19,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"p1header"},{"code":"missing-required","component":"IconText","path":"/title","message":"missing required field \"/title\" — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"p1header"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1312,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":true,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month"},"partial":true,"hasDynamicProps":false,"statementId":"p1body"}],"footer":null},"partial":true,"hasDynamicProps":false,"statementId":"p1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"productCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["p1footer","p2"],"orphaned":[],"statementCount":21,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1476,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":true,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":true,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":true,"hasDynamicProps":true,"statementId":"p1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["p2"],"orphaned":[],"statementCount":23,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1640,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":true,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":true,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Pro"}]}]}]},"variant":"secondary"},"partial":true,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":true,"hasDynamicProps":true,"statementId":"p1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-mini","header":null,"body":[],"footer":null},"partial":true,"hasDynamicProps":false,"statementId":"p2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["p2icon","p2body","p2footer"],"orphaned":[],"statementCount":25,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"p2header"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1804,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":false,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":false,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Pro"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":false,"hasDynamicProps":true,"statementId":"p1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-mini","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"box","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p2icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Mini","subtitle":"New arrival","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p2header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"980 units","subtext":"Sold this month","trend":{"direction":"up","value":4}},"partial":false,"hasDynamicProps":false,"statementId":"p2body"}],"footer":null},"partial":false,"hasDynamicProps":false,"statementId":"p2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["p2footer"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1962,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":false,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":false,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Pro"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":false,"hasDynamicProps":true,"statementId":"p1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-mini","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"box","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p2icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Mini","subtitle":"New arrival","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p2header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"980 units","subtext":"Sold this month","trend":{"direction":"up","value":4}},"partial":false,"hasDynamicProps":false,"statementId":"p2body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$14.00","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Mini"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true,"statementId":"p2btn"}}},"partial":false,"hasDynamicProps":true,"statementId":"p2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":29,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"openui-example-6","schema":"openui","input":"Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])","checkpoints":[{"at":142,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Te"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["editTable","formHeader","prefsForm"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":284,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text"}],"data":[]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["colRole","colStart","row1","row2","formHeader","prefsForm"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":426,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"en"}]}],"data":[]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["roleDesign","colStart","row1","row2","formHeader","prefsForm"],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":568,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Da"}],"data":[]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["row1","row2","formHeader","prefsForm"],"orphaned":[],"statementCount":8,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":710,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":false,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":false,"hasDynamicProps":false,"statementId":"editTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["formHeader","prefsForm"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":852,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","fc2"],"orphaned":[],"statementCount":13,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"fc1"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":994,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","style2","fc2"],"orphaned":[],"statementCount":15,"errors":[{"code":"missing-required","component":"OptionCard","path":"/title","message":"missing required field \"/title\" — signature: OptionCard(value*: string, title*: string, subtitle: string, topContent, disabled: boolean)","statementId":"style1"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1136,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","fc2"],"orphaned":[],"statementCount":17,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1278,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":false,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":false,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":false,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["formButtons","toolChips"],"orphaned":[],"statementCount":19,"errors":[{"code":"null-required","component":"FormControl","path":"/input","message":"required field \"/input\" cannot be null — signature: FormControl(label*: string, input*, hint: string)","statementId":"fc2"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1420,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","tool2","tool3"],"orphaned":[],"statementCount":22,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1562,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","tool3"],"orphaned":[],"statementCount":25,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1699,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":false,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":false,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":false,"hasDynamicProps":false,"statementId":"formHeader"},{"type":"element","typeName":"Form","props":{"name":"prefs","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Save preferences"}]}]}]},"variant":"primary"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Working Style","input":{"type":"element","typeName":"OptionCards","props":{"name":"style","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"focused","title":"Deep Focus","subtitle":"Long uninterrupted blocks","topContent":{"type":"element","typeName":"Icon","props":{"name":"target","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"style1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"style1"},{"type":"element","typeName":"OptionCard","props":{"value":"collab","title":"Collaborative","subtitle":"Frequent pairing and syncs","topContent":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"style2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"style2"}]},"partial":false,"hasDynamicProps":false,"statementId":"styleCards"},"hint":"Pick the one that fits best"},"partial":false,"hasDynamicProps":false,"statementId":"fc1"},{"type":"element","typeName":"FormControl","props":{"label":"Tools","input":{"type":"element","typeName":"Chips","props":{"name":"tools","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"figma","label":"Figma","icon":{"type":"element","typeName":"Icon","props":{"name":"figma","category":"design"},"partial":false,"hasDynamicProps":false,"statementId":"tool1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool1"},{"type":"element","typeName":"ChipItem","props":{"value":"slack","label":"Slack","icon":{"type":"element","typeName":"Icon","props":{"name":"message-square","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"tool2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool2"},{"type":"element","typeName":"ChipItem","props":{"value":"notion","label":"Notion","icon":{"type":"element","typeName":"Icon","props":{"name":"notebook","category":"text"},"partial":false,"hasDynamicProps":false,"statementId":"tool3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool3"}]},"partial":false,"hasDynamicProps":false,"statementId":"toolChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fc2"}]},"partial":false,"hasDynamicProps":true,"statementId":"prefsForm"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"basic","schema":"test","input":"root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Bu"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Button","path":"/label","message":"missing required field \"/label\" — signature: Button(label*: string, action, variant: \"primary\"|\"secondary\")","statementId":"b1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-required","schema":"test","input":"root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["B"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Button"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":51,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"null-required-with-default","schema":"test","input":"root = Card([t1])\nt1 = Text(null)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"required-default-fills","schema":"test","input":"root = Card([x])\nx = Tagged(1, true, \"x\", null)","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tag"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":null,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-component","schema":"test","input":"root = Card([Mystery(\"a\"), Text(\"b\")])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mys"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mystery"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"excess-args","schema":"test","input":"root = Card([Text(\"a\", \"m\", \"extra\", 4)])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":41,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"type-mismatch-scalar","schema":"test","input":"root = Card([Text(42)], 7)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/title","message":"field \"/title\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-mismatch","schema":"test","input":"root = Card([Text(\"a\", \"xl\"), Button(\"b\", null, \"tertiary\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Button"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"terti"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"tertiary"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/size","message":"field \"/size\" expects one of [\"s\", \"m\", \"l\"] but got \"xl\"","statementId":"root"},{"code":"type-mismatch","component":"Button","path":"/variant","message":"field \"/variant\" expects one of [\"primary\", \"secondary\"] but got \"tertiary\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"enum-partial-deferred","schema":"test","input":"root = Card([Text(\"a\", \"x","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"integer-boolean-const","schema":"test","input":"root = Card([x])\nx = Tagged(1.5, \"yes\", \"y\", \"loud\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tagg"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":{"k":"Member","obj":{"k":"Num","v":1},"field":"?"},"tone":"neutral"},"partial":true,"hasDynamicProps":true,"statementId":"x"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"loud"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"loud"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"},{"code":"type-mismatch","component":"Tagged","path":"/kind","message":"field \"/kind\" expects one of [\"x\"] but got \"y\"","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"nested-object","schema":"test","input":"root = Card([c1, c2, c3])\nc1 = Chart([\"a\"], [1], {unit: \"kg\"})\nc2 = Chart([\"a\"], [1], {scale: 2})\nc3 = Chart([\"a\"], [1], {unit: 5, scale: \"big\"})","checkpoints":[{"at":13,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c1","c2","c3"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"un":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":65,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":78,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":91,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scal":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c2"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":104,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":117,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":130,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":143,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":145,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c3"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"},{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"array-items-pruned","schema":"test","input":"root = Card([Chart([\"a\", 2, \"c\"], [1, \"x\", 3])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"element-in-data-slot","schema":"test","input":"root = Card([Chart([Text(\"a\")], [1])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unresolved-and-orphaned","schema":"test","input":"root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a","miss"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":58,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cycle","schema":"test","input":"root = Card([a])\na = Card([b])\nb = Card([a])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"b"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"self-reference","schema":"test","input":"root = Card([root])","checkpoints":[{"at":2,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["r"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["roo"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"no-root-first-component","schema":"test","input":"x = 1\nmain = Card([Text(\"a\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["main"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"main"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"root-name-statement","schema":"test","input":"Card = Card([Text(\"named\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"Card"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"n"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"duplicate-ids","schema":"test","input":"root = Card([a])\na = Text(\"first\")\na = Text(\"second\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fir"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":53,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"only-prose","schema":"test","input":"Here is your UI, it will appear below.","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"whitespace","schema":"test","input":" \n\t \n","checkpoints":[{"at":1,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fences-and-prose","schema":"test","input":"Sure! Here it is:\n```openui\nroot = Card([a])\na = Text(\"fenced\")\n```\nAnything else?","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"f"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":82,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiple-fences","schema":"test","input":"```\nroot = Card([a])\n```\nand\n```\na = Text(\"second block\")\n```","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"secon"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second bloc"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unclosed-fence","schema":"test","input":"```openui\nroot = Card([a])\na = Text(\"str","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"str"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"fence-in-string","schema":"test","input":"root = Card([a])\na = Text(\"use ``` to fence\")","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"u"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use `"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` t"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fe"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"comments","schema":"test","input":"root = Card([a]) // trailing\n# full line\na = Text(\"not // a comment # here\")\n// done","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not /"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a com"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment #"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"crlf","schema":"test","input":"root = Card([a])\r\na = Text(\"windows\")\r\n","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"wind"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"string-escapes","schema":"test","input":"root = Card([a, b, c, d])\na = Text(\"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83d\\ude00\")\nb = Text('single \\' quote \\n esc \\q')\nc = Text(\"bad \\x escape\")\nd = Text(\"emoji 😀 and é and 漢字\")","checkpoints":[{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nqu"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ uni"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":112,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' qu"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":128,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x"},"partial":true,"hasDynamicProps":false,"statementId":"c"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["d"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":160,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":176,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":true,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and"},"partial":true,"hasDynamicProps":false,"statementId":"d"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":187,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and é and 漢字"},"partial":false,"hasDynamicProps":false,"statementId":"d"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"emoji-outside-strings","schema":"test","input":"root = Card([a]) 😀\na = Text(\"ok\") ✅","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-string","schema":"test","input":"root = Card([a])\na = Text(\"streaming tex","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"s"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"strea"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming tex"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unterminated-escape","schema":"test","input":"root = Card([a])\na = Text(\"ends with \\","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with \\"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"numbers","schema":"test","input":"root = Card([Chart([\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"], [-3, 1.5, 1e3, 007, -0, 2.5e-3])])\n$x = 1e\n$y = 1E+2\n$z = 3.","checkpoints":[{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Chart"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,0]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,{"k":"Member","obj":{"k":"Num","v":2},"field":"?"},null]},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":81,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$x":null},"queryStatements":[],"mutationStatements":[]}},{"at":99,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$x":null,"$y":100},"queryStatements":[],"mutationStatements":[]}},{"at":106,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$x":null,"$y":100,"$z":{"k":"Member","obj":{"k":"Num","v":3},"field":"?"}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"operators","schema":"test","input":"$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])","checkpoints":[{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$a":1},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":""}}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"ye"},"else":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":88,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":92,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"multiline-ternary","schema":"test","input":"$on = true\nroot = Card([t])\nt = Text($on\n ? \"enabled\"\n : \"disabled\")","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"StateRef","n":"$on"}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"en"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabl"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabled"}}},"partial":false,"hasDynamicProps":true,"statementId":"t"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}}]},{"name":"member-index","schema":"test","input":"$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"row":null}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":""}]}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":null,"?":null}]}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key":null}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"row"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":139,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key x"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"builtins","schema":"test","input":"$items = [3, 1, 2]\nroot = Card([Text(\"\" + @Count($items)), Text(\"\" + @Sum($items)), Text(@Round(2.555, 2) + \"\")])\nbare = Count($items)","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3]},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Count"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Count"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Su"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Su"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Comp","name":"Round","args":[]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":134,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"actions","schema":"test","input":"$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))","checkpoints":[{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Card"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1","b2","b3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Ac","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Ph","n":"ToAssistant"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ToAssistant","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":126,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Ph","n":"Res"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Res","b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":162,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["But"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Action"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":198,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https:"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":215,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https://openui.com"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b3"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}}]},{"name":"each","schema":"test","input":"$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))","checkpoints":[{"at":10,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[]},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a"}]},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["f","f"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"ti":null,"?":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b"}]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["Each"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ph","n":"t"}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[],"mappedProps":{}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":110,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":113,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}}]},{"name":"query-mutation","schema":"test","input":"$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])","checkpoints":[{"at":19,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["users"],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":57,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"Null"}],["?",{"k":"Null"}]]},"defaultsAST":null,"refreshAST":null,"deps":["$q"],"complete":true}],"mutationStatements":[]}},{"at":76,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":null,"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":95,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["save"],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":114,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"Null"}],["?",{"k":"Null"}]]}}]}},{"at":133,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":152,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"le"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":171,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["B"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":190,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Actio"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":209,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Ph","n":"Run"}]}]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Run"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":221,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"users","refType":"query"}]}]}]}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}}]},{"name":"state-query","schema":"test","input":"$data = Query(\"get\", {})\nroot = Card([Text(\"x\")])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Qu","Qu"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":null},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":""},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":25,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}}]},{"name":"inline-query","schema":"test","input":"root = Card([Text(Query(\"get\", {}))])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Qu"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":37,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"assignment","schema":"test","input":"$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Inpu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"na"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"excess-args","component":"Input","path":"","message":"Input takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$valu"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$valu":null},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$value"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$value":null},"queryStatements":[],"mutationStatements":[]}}]},{"name":"object-key-order","schema":"test","input":"$o = {b: 1, 2: \"two\", a: 3, 1: \"one\", \"10\": 10}\nroot = Card([Text(\"x\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{}},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"tw","b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"two","b":1,"a":null}},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":null,"2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":null,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}}]},{"name":"missing-commas","schema":"test","input":"root = Card([Text(\"a\") Text(\"b\"), Text(\"c\"),])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":46,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"lowercase-builtin-name","schema":"test","input":"root = Card([Text(@first([1]))])","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fi"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["first"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"unknown-tokens","schema":"test","input":"root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"combining-characters","schema":"test","input":"root = Card([Text(\"e\\u0301 cafe\\u0301\"), Text(\"한국어\"), Text(\"ok\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u03"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é caf"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u0301 cafe\\u030"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-call","schema":"test","input":"root = Card([a, b])\na = Text(\"one\")\nb = Button(\"tw","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","b"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Butto"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Button","props":{"label":"tw"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"truncated-mid-object","schema":"test","input":"root = Card([Chart([\"a\"], [1], {unit: \"k","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":null,"?":null}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"k"}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"data-in-component-slot","schema":"test","input":"root = Card([Text(\"hi\"), { text: \"a\" }, \"b\", 3, [Text(\"x\")], true])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/5","message":"field \"/children/5\" expects Text | Button | Chart but got boolean","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":67,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/5","message":"field \"/children/5\" expects Text | Button | Chart but got boolean","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"data-in-component-slot-via-ref","schema":"test","input":"root = Card(items)\nitems = [{ text: \"a\" }]","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["item"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["items"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["items"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"hoisted-data-def","schema":"hoisted","input":"root = Tree({ label: \"a\" })","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Tr"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Tree","path":"/node","message":"missing required field \"/node\" — signature: Tree(node*: __schema0)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"l":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"labe":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":"a"}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":"a"}},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]},{"name":"cloud-envelope","schema":"chat","input":"]]>openui:content?thesys=true\n```openui-lang\nroot = Card([h, t])\nh = CardHeader(\"Q3\", \"Revenue\")\nt = TextContent(\"Up 12%\")\n```\n]]>openui:end","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["h"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car","t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3"},"partial":true,"hasDynamicProps":false,"statementId":"h"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["TextCon"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":true,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":true,"hasDynamicProps":false,"statementId":"t"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":140,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}] +[ +{"name":"chat-example-1","schema":"chat","input":"Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }","checkpoints":[{"at":607,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["highlights","statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1214,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["statsHeader","statsCards","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1821,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","valu":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ov2","ov3","sectionsBlock","actionBtns","src1","src2"],"orphaned":[],"statementCount":13,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2428,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[],"isFoldable":null},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secLandmarks","secFood","secWhen","f","actionBtns","src1","src2"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3035,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":null,"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["lm1tagIcon","lm2","lm3","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3642,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["lm3body","lm3tag","lm4","secFood","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":33,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"lm3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["foodCards","secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4856,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Sh"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["secWhen","actionBtns","src1","src2"],"orphaned":[],"statementCount":45,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5463,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"P"},"partial":true,"hasDynamicProps":false,"statementId":"sp2"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sp3","tabSummer","actionBtns","src1","src2"],"orphaned":[],"statementCount":51,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6070,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Sein"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["su2","su3","actionBtns","src1","src2"],"orphaned":[],"statementCount":55,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6677,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":true,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":true,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":true,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":true,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":true,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":true,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":true,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":true,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":true,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":true,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":true,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":true,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":true,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":true,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":true,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":true,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":true,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"springList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":true,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":true,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":true,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":true,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":true,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{}},"partial":true,"hasDynamicProps":false,"statementId":"btn2"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btn3","src1","src2"],"orphaned":[],"statementCount":60,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7277,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Paris","subtitle":"The City of Light · France's Eternal Capital"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2]."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"art-museums","title":"Art & Museums","body":"143 museums including the Louvre & newly reopened Grand Palais.","bgColor":"gray","bgImageSrc":"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"gastronomy","title":"Gastronomy","body":"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.","bgColor":"gray"},"partial":false,"hasDynamicProps":false,"statementId":"h2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fashion-capital","title":"Fashion Capital","body":"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.","bgColor":"gray","bgImageSrc":"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"h3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this aspect of Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"highlights"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Paris by the Numbers","description":"Key visitor statistics"},"partial":false,"hasDynamicProps":false,"statementId":"statsHeader"},{"type":"element","typeName":"OverviewCardBlock","props":{"items":[{"type":"element","typeName":"OverviewCardItem","props":{"id":"annual-visitors","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"ov1icon"},"iconVariant":"neutral","iconSize":"m","title":"Annual Visitors","subtitle":"2024 arrivals","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov1top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"48.7M","subtext":"tourists","trend":{"direction":"up","value":2.5}},"partial":false,"hasDynamicProps":false,"statementId":"ov1metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov1"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"museums-monuments","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ov2icon"},"iconVariant":"neutral","iconSize":"m","title":"Museums & Monuments","subtitle":"Cultural sites","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov2top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,370+","subtext":"across the city"},"partial":false,"hasDynamicProps":false,"statementId":"ov2metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov2"},{"type":"element","typeName":"OverviewCardItem","props":{"id":"tourism-revenue","top":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"ov3icon"},"iconVariant":"neutral","iconSize":"m","title":"Tourism Revenue","subtitle":"2024 estimate","bold":false,"layout":"vertical"},"partial":false,"hasDynamicProps":false,"statementId":"ov3top"},"bottom":{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"€23.4B","subtext":"generated"},"partial":false,"hasDynamicProps":false,"statementId":"ov3metric"}},"partial":false,"hasDynamicProps":false,"statementId":"ov3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"statsCards"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"landmarks","trigger":"Iconic Landmarks","content":[{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Eiffel Tower","subtext":"Open daily 9am–midnight","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm1body"},"id":"eiffel-tower","bgImageSrc":"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Must-See","icon":{"type":"element","typeName":"Icon","props":{"name":"star","category":"shapes"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tagIcon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"lm1tag"},"bgImageAlt":"Aerial view of the Eiffel Tower"},"partial":false,"hasDynamicProps":false,"statementId":"lm1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"The Louvre","subtext":"World's largest art museum","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm2body"},"id":"the-louvre","bgImageSrc":"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"8.9M visits/yr","icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tagIcon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"lm2tag"},"bgImageAlt":"Exterior of the Louvre museum"},"partial":false,"hasDynamicProps":false,"statementId":"lm2"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Notre-Dame","subtext":"Fully restored cathedral","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm3body"},"id":"notre-dame","bgImageSrc":"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Reopened 2024","icon":{"type":"element","typeName":"Icon","props":{"name":"hammer","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tagIcon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"lm3tag"},"bgImageAlt":"Notre-Dame cathedral facade"},"partial":false,"hasDynamicProps":false,"statementId":"lm3"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Palace of Versailles","subtext":"Royal gardens & grand halls","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"lm4body"},"id":"versailles","bgImageSrc":"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Day Trip","icon":{"type":"element","typeName":"Icon","props":{"name":"train-front","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tagIcon"},"size":"sm","variant":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"lm4tag"},"bgImageAlt":"Latona Fountain at Versailles"},"partial":false,"hasDynamicProps":false,"statementId":"lm4"}],"layout":"carousel","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this Paris landmark"}},"partial":false,"hasDynamicProps":false,"statementId":"landmarksCarousel"}]},"partial":false,"hasDynamicProps":false,"statementId":"secLandmarks"},{"type":"element","typeName":"SectionItem","props":{"value":"food","trigger":"Food & Drink","content":[{"type":"element","typeName":"ContextCardBlock","props":{"items":[{"type":"element","typeName":"ContextCardItem","props":{"id":"bistros","title":"Bistros","body":"Classic French fare — try Les Arlots for confit beef cheeks.","bgColor":"gray","bgImageSrc":"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp"},"partial":false,"hasDynamicProps":false,"statementId":"f1"},{"type":"element","typeName":"ContextCardItem","props":{"id":"fine-dining","title":"Fine Dining","body":"Septime leads a new wave of creative Michelin-starred cuisine.","bgColor":"gray","bgImageSrc":"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f2"},{"type":"element","typeName":"ContextCardItem","props":{"id":"bakeries","title":"Bakeries","body":"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.","bgColor":"gray","bgImageSrc":"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg"},"partial":false,"hasDynamicProps":false,"statementId":"f3"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about eating and drinking in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"foodCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"secFood"},{"type":"element","typeName":"SectionItem","props":{"value":"when","trigger":"Best Time to Visit","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"spring","trigger":"Spring","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Cherry blossoms at Parc de Sceaux","subtitle":"March – May","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about cherry blossom season in Paris"}},"partial":false,"hasDynamicProps":false,"statementId":"sp1"},{"type":"element","typeName":"ListItem","props":{"title":"Picnics along the Seine & in city parks","subtitle":"Warm, lively atmosphere","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Where are the best picnic spots in Paris?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp2"},{"type":"element","typeName":"ListItem","props":{"title":"Fewer crowds than summer","subtitle":"Ideal for sightseeing","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"How busy is Paris in spring?"}},"partial":false,"hasDynamicProps":false,"statementId":"sp3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"springList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSpring"},{"type":"element","typeName":"TabItem","props":{"value":"summer","trigger":"Summer","content":[{"type":"element","typeName":"ListBlock","props":{"items":[{"type":"element","typeName":"ListItem","props":{"title":"Swim in the Seine — open July & August 2026","subtitle":"First time in 102 years","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about swimming in the Seine"}},"partial":false,"hasDynamicProps":false,"statementId":"su1"},{"type":"element","typeName":"ListItem","props":{"title":"Open-air cinema at Parc de la Villette","subtitle":"Free films under the stars","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"Tell me about the open-air cinema at Parc de la Villette"}},"partial":false,"hasDynamicProps":false,"statementId":"su2"},{"type":"element","typeName":"ListItem","props":{"title":"Bastille Day celebrations on July 14","subtitle":"Fireworks at the Eiffel Tower","image":null,"actionLabel":null,"action":{"type":"continue_conversation","context":"What happens in Paris on Bastille Day?"}},"partial":false,"hasDynamicProps":false,"statementId":"su3"}],"variant":"number"},"partial":false,"hasDynamicProps":false,"statementId":"summerList"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabSummer"}]},"partial":false,"hasDynamicProps":false,"statementId":"whenTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secWhen"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sectionsBlock"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan a Trip to Paris","action":{"type":"continue_conversation","context":"Help me plan a trip to Paris"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btn1"},{"type":"element","typeName":"Button","props":{"label":"Best Hotels in Paris","action":{"type":"continue_conversation","context":"Show me the best hotels in Paris"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn2"},{"type":"element","typeName":"Button","props":{"label":"Build a Paris Itinerary","action":{"type":"continue_conversation","context":"Build a 5-day Paris itinerary for me"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btn3"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionBtns"}],"sources":[{"title":"Paris Travel Guide 2025","sourceName":"Travel and Tour World","url":"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/"},{"title":"Best Things to Do in Paris 2026","sourceName":"Time Out Paris","url":"http://www.timeout.fr/paris/en/for-tourists"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"chat-example-2","schema":"chat","input":"Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")","checkpoints":[{"at":510,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpi1icon","kpi1rhs","kpi2","kpi3","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi1lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1020,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3icon","kpi3rhs","kpi4","sections","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":13,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi3lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1530,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabGrowth","t","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2040,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["retentio","secChannels","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2550,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":35,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3060,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tab","deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":41,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3570,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Sta"]},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["deepDiveHeader","compositeCards","actionButtons"],"orphaned":[],"statementCount":47,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4080,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":null,"body":[]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["supportIcon","supportMetric","supportChart","supportList","cardMarketing","actionButtons"],"orphaned":[],"statementCount":51,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"supportHeader"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4590,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","rig":null}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["sup2","sup3","cardMarketing","actionButtons"],"orphaned":[],"statementCount":58,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["marketingMetric","marketingChart","marketingList","actionButtons"],"orphaned":[],"statementCount":63,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":true,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":true,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":true,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":true,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":true,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":true,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":true,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":true,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":true,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":true,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":true,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":true,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":true,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":true,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":true,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":true,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":true,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":true,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":true,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":true,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":true,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":true,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":true,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":true,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Co"}],"size":"small"},"partial":true,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":true,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":true,"hasDynamicProps":false,"statementId":"compositeCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["mkt3","actionButtons"],"orphaned":[],"statementCount":70,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6118,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Analytics Dashboard","subtitle":"April 2026 · Business Performance Overview"},"partial":false,"hasDynamicProps":false,"statementId":"pageHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"total-revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Total Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$284,500","subtext":"+12.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"Monthly active users","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"47,320","subtext":"+6.8%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"conversion-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"trending-up","category":"charts"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Conversion Rate","subtitle":"Avg. this month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"5.7%","subtext":"+0.9%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn-rate","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn Rate","subtitle":"Monthly customer churn","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"2.1%","subtext":"-0.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi4rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi4"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"SectionBlock","props":{"sections":[{"type":"element","typeName":"SectionItem","props":{"value":"users","trigger":"User Activity","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"growth","trigger":"User Growth","content":[{"type":"element","typeName":"LineChart","props":{"labels":["May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"DAU","values":[5.1,5.4,5.8,6.2,6.7,7.1,7.6,8,8.4,8.9,9.3,9.8]},"partial":false,"hasDynamicProps":false,"statementId":"dauSeries"},{"type":"element","typeName":"Series","props":{"category":"MAU","values":[28.4,30.1,31.8,33.5,35.2,37.1,38.8,40.4,42.1,43.9,45.6,47.3]},"partial":false,"hasDynamicProps":false,"statementId":"mauSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Users (k)"},"partial":false,"hasDynamicProps":false,"statementId":"growthChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabGrowth"},{"type":"element","typeName":"TabItem","props":{"value":"retention","trigger":"Cohort Retention","content":[{"type":"element","typeName":"LineChart","props":{"labels":["Month 0","Month 1","Month 2","Month 3","Month 4","Month 5","Month 6"],"series":[{"type":"element","typeName":"Series","props":{"category":"Jan Cohort","values":[100,80,70,62,56,51,47]},"partial":false,"hasDynamicProps":false,"statementId":"cohortJan"},{"type":"element","typeName":"Series","props":{"category":"Feb Cohort","values":[100,83,73,65,59,54,50]},"partial":false,"hasDynamicProps":false,"statementId":"cohortFeb"},{"type":"element","typeName":"Series","props":{"category":"Mar Cohort","values":[100,86,76,68,62,0,0]},"partial":false,"hasDynamicProps":false,"statementId":"cohortMar"}],"variant":"natural","xLabel":"Month Since Signup","yLabel":"Retention (%)"},"partial":false,"hasDynamicProps":false,"statementId":"retentionChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabRetention"}]},"partial":false,"hasDynamicProps":false,"statementId":"userTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secUsers"},{"type":"element","typeName":"SectionItem","props":{"value":"channels","trigger":"Acquisition Channels","content":[{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"channel-bar","trigger":"Revenue by Channel","content":[{"type":"element","typeName":"HorizontalBarChart","props":{"labels":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"series":[{"type":"element","typeName":"Series","props":{"category":"Revenue ($k)","values":[82.4,68.1,54.6,38.2,26.8,14.4]},"partial":false,"hasDynamicProps":false,"statementId":"channelSeries"}],"variant":"grouped","xLabel":"Revenue ($k)","yLabel":"Channel"},"partial":false,"hasDynamicProps":false,"statementId":"channelBarChart"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelBar"},{"type":"element","typeName":"TabItem","props":{"value":"channel-table","trigger":"Full Breakdown","content":[{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Channel","data":["Organic Search","Paid Ads","Referral Program","Partner Network","Direct / Brand","Email Campaigns"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colChannel"},{"type":"element","typeName":"Col","props":{"label":"Leads","data":[4210,3180,2050,1120,1290,820],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colLeads"},{"type":"element","typeName":"Col","props":{"label":"Conv. Rate","data":["6.4%","5.1%","9.4%","11.8%","5.8%","8.1%"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colConv"},{"type":"element","typeName":"Col","props":{"label":"CAC ($)","data":[188,395,132,109,218,154],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colCac"},{"type":"element","typeName":"Col","props":{"label":"Revenue ($k)","data":[82.4,68.1,54.6,38.2,26.8,14.4],"type":"number"},"partial":false,"hasDynamicProps":false,"statementId":"colRevenue"},{"type":"element","typeName":"Col","props":{"label":"Status","data":["Scaling","Optimizing","Scaling","Growing","Stable","Stable"],"type":"string"},"partial":false,"hasDynamicProps":false,"statementId":"colStatus"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabChannelTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"channelTabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"secChannels"}],"isFoldable":false},"partial":false,"hasDynamicProps":false,"statementId":"sections"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Support Health & Marketing ROI","description":"Click a card to explore deeper insights"},"partial":false,"hasDynamicProps":false,"statementId":"deepDiveHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"support-health","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"headphones","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"supportIcon"},"iconVariant":"neutral","iconSize":"m","title":"Support Health","subtitle":"Ticket volume & resolution trends","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"supportHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"94.2% CSAT","subtext":"Customer Satisfaction Score","trend":{"direction":"up","value":2.1}},"partial":false,"hasDynamicProps":false,"statementId":"supportMetric"},{"type":"element","typeName":"BarChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Opened","values":[341,327,308,289]},"partial":false,"hasDynamicProps":false,"statementId":"openSeries"},{"type":"element","typeName":"Series","props":{"category":"Resolved","values":[319,318,301,283]},"partial":false,"hasDynamicProps":false,"statementId":"resolvedSeries"}],"variant":"grouped","xLabel":"Month","yLabel":"Tickets"},"partial":false,"hasDynamicProps":false,"statementId":"supportChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Avg. Resolution Time","right":"4h 12m","rightVariant":"text"},{"left":"First Contact Resolution","right":"78.4%","rightVariant":"number"},{"left":"Escalation Rate","right":"6.2%","rightVariant":"number"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"supportList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardSupport"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"marketing-roi","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"megaphone","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"marketingIcon"},"iconVariant":"neutral","iconSize":"m","title":"Marketing ROI","subtitle":"Spend vs. pipeline generated","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"marketingHeader"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"3.8x Blended ROI","subtext":"Return on Ad Spend","trend":{"direction":"up","value":0.4}},"partial":false,"hasDynamicProps":false,"statementId":"marketingMetric"},{"type":"element","typeName":"AreaChart","props":{"labels":["Jan","Feb","Mar","Apr"],"series":[{"type":"element","typeName":"Series","props":{"category":"Ad Spend","values":[44,46.8,49.2,51.6]},"partial":false,"hasDynamicProps":false,"statementId":"spendSeries"},{"type":"element","typeName":"Series","props":{"category":"Pipeline Generated","values":[158.2,171.5,184.9,196.1]},"partial":false,"hasDynamicProps":false,"statementId":"pipelineSeries"}],"variant":"natural","xLabel":"Month","yLabel":"Value ($k)"},"partial":false,"hasDynamicProps":false,"statementId":"marketingChart"},{"type":"element","typeName":"EntityList","props":{"rows":[{"left":"Total Ad Spend (Apr)","right":"$51,600","rightVariant":"number"},{"left":"Cost per Lead","right":"$48.20","rightVariant":"number"},{"left":"Top Channel","right":"Organic Search","rightVariant":"text"}],"size":"small"},"partial":false,"hasDynamicProps":false,"statementId":"marketingList"}]},"partial":false,"hasDynamicProps":false,"statementId":"cardMarketing"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Explore this deep-dive area in more detail"}},"partial":false,"hasDynamicProps":false,"statementId":"compositeCards"},{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Break Down by Channel","action":{"type":"continue_conversation","context":"Break down this month's revenue by acquisition channel"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnChannels"},{"type":"element","typeName":"Button","props":{"label":"Forecast Next Quarter","action":{"type":"continue_conversation","context":"Forecast revenue and active users for next quarter"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnForecast"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"actionButtons"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":74,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"chat-example-3","schema":"chat","input":"Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)","checkpoints":[{"at":361,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas"},"partial":true,"hasDynamicProps":false,"statementId":"header"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","inspoCards","form"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":722,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["i","insp2","form"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"insp1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1083,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2","form"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1444,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":null,"size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["insp2icon","form"],"orphaned":[],"statementCount":11,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1805,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btnSkip","fcDestination","fcDates","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":15,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2166,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Fo","fcTravellers","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":19,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2527,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tr1","tr2","tr3","tr4","fcTripType","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":22,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2888,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["oc2","oc3","oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":29,"errors":[{"code":"missing-required","component":"OptionCard","path":"/title","message":"missing required field \"/title\" — signature: OptionCard(value*: string, title*: string, subtitle: string, topContent, disabled: boolean)","statementId":"oc1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3249,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["oc4","fcBudget","fcStay","fcNotes"],"orphaned":[],"statementCount":34,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3610,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fcNotes"],"orphaned":[],"statementCount":39,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"fcStay"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3971,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":true,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":true,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":true,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":true,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":true,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":true,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":true,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":true,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":true,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":true,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":true,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":true,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":true,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":true,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":true,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":true,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":true,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":true,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":true,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":true,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":true,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":true,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":null},"partial":true,"hasDynamicProps":false,"statementId":"ch3"}],"rules":{},"defaultValue":["hotel"]},"partial":true,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":true,"hasDynamicProps":false,"statementId":"fcStay"}]},"partial":true,"hasDynamicProps":false,"statementId":"form"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ch4","fcNotes"],"orphaned":[],"statementCount":46,"errors":[{"code":"missing-required","component":"Icon","path":"/name","message":"missing required field \"/name\" — signature: Icon(name*: string, category: string)","statementId":"ch3icon"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4322,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Plan Your Trip","subtitle":"A few ideas to spark inspiration — then tell me your preferences"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"Tap a style to jump straight in, or fill the quick form below for a tailored plan."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tropical Beach Escape","subtext":"Overwater villas & snorkeling","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp1body"},"id":"inspo-beach","bgImageSrc":"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Relaxation","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"insp1icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"insp1tag"},"bgImageAlt":"Maldives overwater villas"},"partial":false,"hasDynamicProps":false,"statementId":"insp1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Mountain Adventure","subtext":"Trekking & epic views","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"insp2body"},"id":"inspo-mountain","bgImageSrc":"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Active","icon":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"insp2icon"},"size":"sm","variant":"warning"},"partial":false,"hasDynamicProps":false,"statementId":"insp2tag"},"bgImageAlt":"Trekking in the Peruvian Andes"},"partial":false,"hasDynamicProps":false,"statementId":"insp2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Plan me a trip in this style with destinations, itinerary, and costs"}},"partial":false,"hasDynamicProps":false,"statementId":"inspoCards"},{"type":"element","typeName":"Form","props":{"name":"trip-planner","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Plan My Trip","action":{"type":"continue_conversation","context":"Help me plan a trip based on my form submission"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSubmit"},{"type":"element","typeName":"Button","props":{"label":"Just Surprise Me","action":{"type":"continue_conversation","context":"Skip the form and surprise me with a destination and itinerary"},"variant":"secondary"},"partial":false,"hasDynamicProps":false,"statementId":"btnSkip"}],"direction":"row"},"partial":false,"hasDynamicProps":false,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Destination","input":{"type":"element","typeName":"Input","props":{"name":"destination","placeholder":"e.g. Tokyo, Japan — or leave blank","type":"text"},"partial":false,"hasDynamicProps":false,"statementId":"destinationInput"},"hint":"Leave blank if you'd like suggestions"},"partial":false,"hasDynamicProps":false,"statementId":"fcDestination"},{"type":"element","typeName":"FormControl","props":{"label":"Travel Dates","input":{"type":"element","typeName":"DatePicker","props":{"name":"travel-dates","mode":"range","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"datesPicker"},"hint":"Select your start and end dates"},"partial":false,"hasDynamicProps":false,"statementId":"fcDates"},{"type":"element","typeName":"FormControl","props":{"label":"Number of Travellers","input":{"type":"element","typeName":"Select","props":{"name":"num-travellers","items":[{"type":"element","typeName":"SelectItem","props":{"value":"1","label":"1 — Solo"},"partial":false,"hasDynamicProps":false,"statementId":"tr1"},{"type":"element","typeName":"SelectItem","props":{"value":"2","label":"2 — Couple"},"partial":false,"hasDynamicProps":false,"statementId":"tr2"},{"type":"element","typeName":"SelectItem","props":{"value":"3-4","label":"3–4 People"},"partial":false,"hasDynamicProps":false,"statementId":"tr3"},{"type":"element","typeName":"SelectItem","props":{"value":"5+","label":"5+ People"},"partial":false,"hasDynamicProps":false,"statementId":"tr4"}],"placeholder":"Select number of travellers","rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"travellersSelect"},"hint":"How many people are travelling?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTravellers"},{"type":"element","typeName":"FormControl","props":{"label":"Trip Type","input":{"type":"element","typeName":"OptionCards","props":{"name":"trip-type","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"adventure","title":"Adventure","subtitle":"Hiking, trekking & outdoor activities","topContent":{"type":"element","typeName":"Icon","props":{"name":"mountain","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc1"},{"type":"element","typeName":"OptionCard","props":{"value":"beach","title":"Beach & Relaxation","subtitle":"Sun, sand & leisure","topContent":{"type":"element","typeName":"Icon","props":{"name":"waves","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"oc2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc2"},{"type":"element","typeName":"OptionCard","props":{"value":"cultural","title":"Cultural & Historical","subtitle":"Museums, heritage & local experiences","topContent":{"type":"element","typeName":"Icon","props":{"name":"landmark","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc3"},{"type":"element","typeName":"OptionCard","props":{"value":"city","title":"City Break","subtitle":"Urban exploration & nightlife","topContent":{"type":"element","typeName":"Icon","props":{"name":"building-2","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"oc4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"oc4"}],"rules":{"required":true}},"partial":false,"hasDynamicProps":false,"statementId":"tripTypeCards"},"hint":"What kind of trip are you planning?"},"partial":false,"hasDynamicProps":false,"statementId":"fcTripType"},{"type":"element","typeName":"FormControl","props":{"label":"Estimated Budget (per person)","input":{"type":"element","typeName":"Slider","props":{"name":"budget","variant":"discrete","min":500,"max":10000,"step":500,"defaultValue":[2500],"label":"Budget (USD)"},"partial":false,"hasDynamicProps":false,"statementId":"budgetSlider"},"hint":"Drag to set your per-person budget in USD"},"partial":false,"hasDynamicProps":false,"statementId":"fcBudget"},{"type":"element","typeName":"FormControl","props":{"label":"Accommodation Preference","input":{"type":"element","typeName":"Chips","props":{"name":"accommodation","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"hotel","label":"Hotel","icon":{"type":"element","typeName":"Icon","props":{"name":"building","category":"buildings"},"partial":false,"hasDynamicProps":false,"statementId":"ch1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch1"},{"type":"element","typeName":"ChipItem","props":{"value":"resort","label":"Resort","icon":{"type":"element","typeName":"Icon","props":{"name":"umbrella","category":"travel"},"partial":false,"hasDynamicProps":false,"statementId":"ch2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch2"},{"type":"element","typeName":"ChipItem","props":{"value":"airbnb","label":"Vacation Rental","icon":{"type":"element","typeName":"Icon","props":{"name":"home","category":"home"},"partial":false,"hasDynamicProps":false,"statementId":"ch3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch3"},{"type":"element","typeName":"ChipItem","props":{"value":"camping","label":"Camping / Glamping","icon":{"type":"element","typeName":"Icon","props":{"name":"tent","category":"nature"},"partial":false,"hasDynamicProps":false,"statementId":"ch4icon"}},"partial":false,"hasDynamicProps":false,"statementId":"ch4"}],"rules":{},"defaultValue":["hotel"]},"partial":false,"hasDynamicProps":false,"statementId":"stayChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fcStay"},{"type":"element","typeName":"FormControl","props":{"label":"Special Requests or Notes","input":{"type":"element","typeName":"TextArea","props":{"name":"special-requests","placeholder":"e.g. vegetarian meals, wheelchair access, honeymoon surprise...","rows":4},"partial":false,"hasDynamicProps":false,"statementId":"notesArea"},"hint":"Any dietary needs, accessibility requirements, or specific interests?"},"partial":false,"hasDynamicProps":false,"statementId":"fcNotes"}]},"partial":false,"hasDynamicProps":false,"statementId":"form"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":50,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"chat-example-4","schema":"chat","input":"Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }","checkpoints":[{"at":218,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Ene"},"partial":true,"hasDynamicProps":false,"statementId":"header"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["intro","posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":436,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to w"},"partial":true,"hasDynamicProps":false,"statementId":"intro"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["posters","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":654,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["v1body","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"VisualCardItem","path":"/body","message":"required field \"/body\" cannot be null — signature: VisualCardItem(body*: BoldText, id: string, bgImageSrc: string, tag: Tag, bgImageAlt: string)","statementId":"v1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":872,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":null,"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v1icon","v2","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1090,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":null,"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["v2tag","linksHeader","trackCards","src1","src2"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1308,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"}],"sources":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["CompositeCard","src1","src2"],"orphaned":[],"statementCount":14,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1526,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1icon","t1body","t1tags","t1btn","t2","src1","src2"],"orphaned":[],"statementCount":16,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t1h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1744,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Wa"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2","src1","src2"],"orphaned":[],"statementCount":20,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1962,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":null,"body":[],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2icon","t2body","t2tags","t2btn","src1","src2"],"orphaned":[],"statementCount":22,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"t2h"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":[]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":null}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t2btn","src1","src2"],"orphaned":[],"statementCount":25,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2398,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":true,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":true,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":true,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":true,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":true,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":true,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":true,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":true,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":true,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":true,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":true,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":true,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceN":null}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["src2"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2615,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Retro-Energetic Indian Tracks","subtitle":"New Hindi releases with 80s/90s dance DNA"},"partial":false,"hasDynamicProps":false,"statementId":"header"},{"type":"element","typeName":"TextContent","props":{"text":"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video."},"partial":false,"hasDynamicProps":false,"statementId":"intro"},{"type":"element","typeName":"VisualCardBlock","props":{"items":[{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Tamma Tamma","subtext":"Dhurandhar · Ranveer Singh","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v1body"},"id":"tamma","bgImageSrc":"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"80s Electro-Disco","icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v1icon"},"size":"sm","variant":"success"},"partial":false,"hasDynamicProps":false,"statementId":"v1tag"},"bgImageAlt":"Tamma Tamma video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v1"},{"type":"element","typeName":"VisualCardItem","props":{"body":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"Sajan Re","subtext":"Nora Fatehi · Badshah","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"v2body"},"id":"sajan","bgImageSrc":"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg","tag":{"type":"element","typeName":"Tag","props":{"text":"Synthwave Electro","icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"v2icon"},"size":"sm","variant":"info"},"partial":false,"hasDynamicProps":false,"statementId":"v2tag"},"bgImageAlt":"Sajan Re video poster"},"partial":false,"hasDynamicProps":false,"statementId":"v2"}],"layout":"grid","responsive":true,"action":{"type":"continue_conversation","context":"Tell me more about this track and its retro influences"}},"partial":false,"hasDynamicProps":false,"statementId":"posters"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Watch the Exact Videos","description":"Each button opens that track's official video"},"partial":false,"hasDynamicProps":false,"statementId":"linksHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-tamma","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"disc-3","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t1icon"},"iconVariant":"neutral","iconSize":"m","title":"Tamma Tamma","subtitle":"Bappi Lahiri classic, electro-funk rework","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t1h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Heavy analog synths and brass over a fast disco groove.","subtext":"Retro Electro-Disco","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t1body"},{"type":"element","typeName":"TagBlock","props":{"tags":["2026 Film Hit","Peak Party"]},"partial":false,"hasDynamicProps":false,"statementId":"t1tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t1btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"t-sajan","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"music","category":"multimedia"},"partial":false,"hasDynamicProps":false,"statementId":"t2icon"},"iconVariant":"neutral","iconSize":"m","title":"Sajan Re","subtitle":"Nora Fatehi · Badshah · Sanjoy","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"t2h"},"body":[{"type":"element","typeName":"Text","props":{"variant":"text","value":"Synthwave melody hooks over a modern club beat.","subtext":"Retro-Fusion Electro","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"t2body"},{"type":"element","typeName":"TagBlock","props":{"tags":["Club Anthem","Nora x Badshah"]},"partial":false,"hasDynamicProps":false,"statementId":"t2tags"}],"footer":{"button":{"type":"element","typeName":"Button","props":{"label":"Watch on YouTube","action":{"type":"open_url","url":"https://www.youtube.com/watch?v=COUSCnFazzc"},"variant":"primary"},"partial":false,"hasDynamicProps":false,"statementId":"t2btn"}}},"partial":false,"hasDynamicProps":false,"statementId":"t2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"trackCards"}],"sources":[{"title":"Tamma Tamma (Full Video) - Dhurandhar","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=PQHeOb0Q9oo"},{"title":"Sajan Re (Official Music Video)","sourceName":"YouTube (T-Series)","url":"https://www.youtube.com/watch?v=COUSCnFazzc"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":28,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"chat-example-5","schema":"chat","input":"Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")","checkpoints":[{"at":37,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":74,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["title","tbl","followUps"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":111,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":""},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tbl","followUps"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":148,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":185,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs","users","followUps"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":222,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Pyth"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years","followUps"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":259,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["years","followUps"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":296,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["followUps"],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":333,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu1"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":370,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me m"},"partial":true,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":true,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fu2"],"orphaned":[],"statementCount":8,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":407,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["FollowUpItem"],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":442,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"},{"type":"element","typeName":"FollowUpBlock","props":{"items":[{"type":"element","typeName":"FollowUpItem","props":{"text":"Tell me more about Python"},"partial":false,"hasDynamicProps":false,"statementId":"fu1"},{"type":"element","typeName":"FollowUpItem","props":{"text":"Show me a JavaScript comparison"},"partial":false,"hasDynamicProps":false,"statementId":"fu2"}]},"partial":false,"hasDynamicProps":false,"statementId":"followUps"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"openui-example-1","schema":"openui","input":"Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]","checkpoints":[{"at":28,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["titl"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["TextContent","tbl"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":112,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-hea"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tbl"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":140,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":168,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"missing-required","component":"Col","path":"/data","message":"missing required field \"/data\" — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":196,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["langs","users","years"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":224,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","Java"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":252,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript"]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["users","years"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"},{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":280,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript","Go"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["years"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Col","path":"/data","message":"required field \"/data\" cannot be null — signature: Col(label*: string, data*, type: \"string\"|\"number\"|\"action\")","statementId":"tbl"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":308,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript","Go"]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1,8.5,5.2]},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":336,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Top Languages","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Table","props":{"columns":[{"type":"element","typeName":"Col","props":{"label":"Language","data":["Python","JavaScript","Java","TypeScript","Go"]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Users (M)","data":[15.7,14.2,12.1,8.5,5.2]},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Col","props":{"label":"Year","data":[1991,1995,1995,2012,2009]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tbl"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"openui-example-2","schema":"openui","input":"Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])","checkpoints":[{"at":22,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["title"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["TextC","chart"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":88,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":""},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["chart"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":110,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["chart"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["labels","s1"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"BarChart","path":"/labels","message":"required field \"/labels\" cannot be null — signature: BarChart(labels*: array, series*: array, variant: \"grouped\"|\"stacked\", xLabel: string, yLabel: string, height: number)","statementId":"chart"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":154,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["labels","s1","s2"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"BarChart","path":"/labels","message":"required field \"/labels\" cannot be null — signature: BarChart(labels*: array, series*: array, variant: \"grouped\"|\"stacked\", xLabel: string, yLabel: string, height: number)","statementId":"chart"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":176,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[],"variant":"grouped"},"partial":true,"hasDynamicProps":false,"statementId":"chart"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["s1","s2"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":198,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[],"variant":"grouped"},"partial":true,"hasDynamicProps":false,"statementId":"chart"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["s2"],"orphaned":[],"statementCount":5,"errors":[{"code":"missing-required","component":"Series","path":"/values","message":"missing required field \"/values\" — signature: Series(category*: string, values*: array)","statementId":"s1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":220,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[{"type":"element","typeName":"Series","props":{"category":"Product A","values":[120,150,180]},"partial":false,"hasDynamicProps":false,"statementId":"s1"}],"variant":"grouped"},"partial":false,"hasDynamicProps":false,"statementId":"chart"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["s2"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":242,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[{"type":"element","typeName":"Series","props":{"category":"Product A","values":[120,150,180]},"partial":true,"hasDynamicProps":false,"statementId":"s1"}],"variant":"grouped"},"partial":true,"hasDynamicProps":false,"statementId":"chart"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[{"code":"missing-required","component":"Series","path":"/values","message":"missing required field \"/values\" — signature: Series(category*: string, values*: array)","statementId":"s2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":261,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Q4 Revenue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"BarChart","props":{"labels":["Oct","Nov","Dec"],"series":[{"type":"element","typeName":"Series","props":{"category":"Product A","values":[120,150,180]},"partial":false,"hasDynamicProps":false,"statementId":"s1"},{"type":"element","typeName":"Series","props":{"category":"Product B","values":[90,110,140]},"partial":false,"hasDynamicProps":false,"statementId":"s2"}],"variant":"grouped"},"partial":false,"hasDynamicProps":false,"statementId":"chart"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"openui-example-3","schema":"openui","input":"Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])","checkpoints":[{"at":74,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","form"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":148,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","nameFi"],"orphaned":[],"statementCount":3,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":222,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","emailField","countryField","msgField"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"nameField"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":296,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btns","emailField","countryField","msgField"],"orphaned":[],"statementCount":4,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":370,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","countryField","msgField"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":444,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","Sel","msgField"],"orphaned":[],"statementCount":6,"errors":[{"code":"null-required","component":"FormControl","path":"/input","message":"required field \"/input\" cannot be null — signature: FormControl(label*: string, input*, hint: string)","statementId":"countryField"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":518,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btns","countryOpts","F"],"orphaned":[],"statementCount":7,"errors":[{"code":"null-required","component":"Select","path":"/items","message":"required field \"/items\" cannot be null — signature: Select(name*: string, items*: array, placeholder: string, rules: object, value: string, size: \"small\"|\"medium\"|\"large\")","statementId":"countryField"},{"code":"null-required","component":"FormControl","path":"/input","message":"required field \"/input\" cannot be null — signature: FormControl(label*: string, input*, hint: string)","statementId":"countryField"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":592,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns","countryOpts"],"orphaned":[],"statementCount":7,"errors":[{"code":"null-required","component":"Select","path":"/items","message":"required field \"/items\" cannot be null — signature: Select(name*: string, items*: array, placeholder: string, rules: object, value: string, size: \"small\"|\"medium\"|\"large\")","statementId":"countryField"},{"code":"null-required","component":"FormControl","path":"/input","message":"required field \"/input\" cannot be null — signature: FormControl(label*: string, input*, hint: string)","statementId":"countryField"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":666,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["btns"],"orphaned":[],"statementCount":8,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":740,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["btns"],"orphaned":[],"statementCount":8,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"form"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":814,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Form","props":{"name":"contact","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Submit","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Submit"}]}]}]},"variant":"primary"},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"btns"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Name","input":{"type":"element","typeName":"Input","props":{"name":"name","placeholder":"Your name","type":"text","rules":{"required":true,"minLength":2}},"partial":true,"hasDynamicProps":false}},"partial":true,"hasDynamicProps":false,"statementId":"nameField"},{"type":"element","typeName":"FormControl","props":{"label":"Email","input":{"type":"element","typeName":"Input","props":{"name":"email","placeholder":"you@example.com","type":"email","rules":{"required":true,"email":true}},"partial":true,"hasDynamicProps":false}},"partial":true,"hasDynamicProps":false,"statementId":"emailField"},{"type":"element","typeName":"FormControl","props":{"label":"Country","input":{"type":"element","typeName":"Select","props":{"name":"country","items":[{"type":"element","typeName":"SelectItem","props":{"value":"us","label":"United States"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"uk","label":"United Kingdom"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"de","label":"Germany"},"partial":true,"hasDynamicProps":false}],"placeholder":"Select...","rules":{"required":true}},"partial":true,"hasDynamicProps":false}},"partial":true,"hasDynamicProps":false,"statementId":"countryField"},{"type":"element","typeName":"FormControl","props":{"label":"Message","input":{"type":"element","typeName":"TextArea","props":{"name":"message","placeholder":"Tell us more...","rows":4,"rules":{"required":true,"minLength":10}},"partial":true,"hasDynamicProps":false}},"partial":true,"hasDynamicProps":false,"statementId":"msgField"}]},"partial":true,"hasDynamicProps":true,"statementId":"form"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Bu"],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":877,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"Contact Us","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Form","props":{"name":"contact","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Submit","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Submit"}]}]}]},"variant":"primary"},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Cancel","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Cancel"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"btns"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Name","input":{"type":"element","typeName":"Input","props":{"name":"name","placeholder":"Your name","type":"text","rules":{"required":true,"minLength":2}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"nameField"},{"type":"element","typeName":"FormControl","props":{"label":"Email","input":{"type":"element","typeName":"Input","props":{"name":"email","placeholder":"you@example.com","type":"email","rules":{"required":true,"email":true}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"emailField"},{"type":"element","typeName":"FormControl","props":{"label":"Country","input":{"type":"element","typeName":"Select","props":{"name":"country","items":[{"type":"element","typeName":"SelectItem","props":{"value":"us","label":"United States"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"uk","label":"United Kingdom"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"SelectItem","props":{"value":"de","label":"Germany"},"partial":false,"hasDynamicProps":false}],"placeholder":"Select...","rules":{"required":true}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"countryField"},{"type":"element","typeName":"FormControl","props":{"label":"Message","input":{"type":"element","typeName":"TextArea","props":{"name":"message","placeholder":"Tell us more...","rows":4,"rules":{"required":true,"minLength":10}},"partial":false,"hasDynamicProps":false}},"partial":false,"hasDynamicProps":false,"statementId":"msgField"}]},"partial":false,"hasDynamicProps":true,"statementId":"form"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":9,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"openui-example-4","schema":"openui","input":"Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]","checkpoints":[{"at":43,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":86,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabs"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"TextContent","path":"/text","message":"missing required field \"/text\" — signature: TextContent(text*: string, size: \"small\"|\"default\"|\"large\"|\"small-heavy\"|\"large-heavy\")","statementId":"title"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":129,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Tabs","path":"/items","message":"missing required field \"/items\" — signature: Tabs(items*: array)","statementId":"tabs"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":172,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["tabVue"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"TabItem","path":"/trigger","message":"missing required field \"/trigger\" — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabReact"},{"code":"missing-required","component":"TabItem","path":"/content","message":"missing required field \"/content\" — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabReact"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":215,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["reactContent","TabIte"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabReact"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":258,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[]},"partial":false,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["reactContent","vueContent"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabReact"},{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabVue"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":301,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta fo"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["vueContent"],"orphaned":[],"statementCount":6,"errors":[{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabVue"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":344,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["vueContent"],"orphaned":[],"statementCount":6,"errors":[{"code":"missing-required","component":"Callout","path":"/description","message":"missing required field \"/description\" — signature: Callout(variant*: \"info\"|\"warning\"|\"error\"|\"success\"|\"neutral\", title*: string, description*: string, visible: boolean)","statementId":"reactContent"},{"code":"null-required","component":"TabItem","path":"/content","message":"required field \"/content\" cannot be null — signature: TabItem(value*: string, trigger*: string, content*: array)","statementId":"tabVue"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":387,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[]},"partial":true,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":430,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[{"type":"element","typeName":"TextContent","props":{"text":"Vue is a progressive framework b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":473,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":true,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[{"type":"element","typeName":"TextContent","props":{"text":"Vue is a progressive framework by Evan You."},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"success","title":"Tip","description":"V"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":true,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":507,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"TextContent","props":{"text":"React vs Vue","size":"large-heavy"},"partial":false,"hasDynamicProps":false,"statementId":"title"},{"type":"element","typeName":"Tabs","props":{"items":[{"type":"element","typeName":"TabItem","props":{"value":"react","trigger":"React","content":[{"type":"element","typeName":"TextContent","props":{"text":"React is a library by Meta for building UIs."},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"info","title":"Note","description":"React uses JSX syntax."},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tabReact"},{"type":"element","typeName":"TabItem","props":{"value":"vue","trigger":"Vue","content":[{"type":"element","typeName":"TextContent","props":{"text":"Vue is a progressive framework by Evan You."},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Callout","props":{"variant":"success","title":"Tip","description":"Vue has a gentle learning curve."},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"tabVue"}]},"partial":false,"hasDynamicProps":false,"statementId":"tabs"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":7,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"openui-example-5","schema":"openui","input":"Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")","checkpoints":[{"at":164,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpiBlock","productsHeader","productCards"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":328,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi1icon","kpi1rhs","kpi2","kpi3","productsHeader","productCards"],"orphaned":[],"statementCount":5,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi1lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":492,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3","productsHeader","productCards"],"orphaned":[],"statementCount":8,"errors":[{"code":"missing-required","component":"SnippetCardItem","path":"/lhs","message":"missing required field \"/lhs\" — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":656,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":null},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["kpi2rhs","kpi3","productsHeader","productCards"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":820,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["kpi3icon","kpi3rhs","productsHeader","productCards"],"orphaned":[],"statementCount":13,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"kpi3lhs"},{"code":"null-required","component":"SnippetCardItem","path":"/lhs","message":"required field \"/lhs\" cannot be null — signature: SnippetCardItem(id: string, lhs*, rhs)","statementId":"kpi3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":984,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Pro"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["productCards"],"orphaned":[],"statementCount":16,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1148,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":null,"body":[],"footer":null},"partial":true,"hasDynamicProps":false,"statementId":"p1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"productCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["p1icon","p1body","p1footer","p2"],"orphaned":[],"statementCount":19,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"p1header"},{"code":"missing-required","component":"IconText","path":"/title","message":"missing required field \"/title\" — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"p1header"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1312,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":true,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month"},"partial":true,"hasDynamicProps":false,"statementId":"p1body"}],"footer":null},"partial":true,"hasDynamicProps":false,"statementId":"p1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"productCards"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["p1footer","p2"],"orphaned":[],"statementCount":21,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1476,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":true,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":true,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":true,"hasDynamicProps":true,"statementId":"p1"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["p2"],"orphaned":[],"statementCount":23,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1640,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":true,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":true,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":true,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":true,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":true,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":true,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":true,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":true,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Pro"}]}]}]},"variant":"secondary"},"partial":true,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":true,"hasDynamicProps":true,"statementId":"p1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-mini","header":null,"body":[],"footer":null},"partial":true,"hasDynamicProps":false,"statementId":"p2"}],"layout":"grid","responsive":true},"partial":true,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["p2icon","p2body","p2footer"],"orphaned":[],"statementCount":25,"errors":[{"code":"null-required","component":"IconText","path":"/icon","message":"required field \"/icon\" cannot be null — signature: IconText(icon*: Icon, iconVariant*: \"neutral\"|\"info\"|\"success\"|\"warning\"|\"danger\"|\"inverted\"|\"filled\"|\"soft\", iconSize*: \"xs\"|\"s\"|\"m\"|\"l\"|\"xl\"|\"sm\"|\"md\"|\"lg\", title*: string, subtitle: string, bold*: boolean, layout*: \"horizontal\"|\"vertical\")","statementId":"p2header"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1804,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":false,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":false,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Pro"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":false,"hasDynamicProps":true,"statementId":"p1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-mini","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"box","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p2icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Mini","subtitle":"New arrival","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p2header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"980 units","subtext":"Sold this month","trend":{"direction":"up","value":4}},"partial":false,"hasDynamicProps":false,"statementId":"p2body"}],"footer":null},"partial":false,"hasDynamicProps":false,"statementId":"p2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["p2footer"],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1962,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"This Month","description":"Key account metrics"},"partial":false,"hasDynamicProps":false,"statementId":"kpiHeader"},{"type":"element","typeName":"SnippetCardBlock","props":{"items":[{"type":"element","typeName":"SnippetCardItem","props":{"id":"revenue","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"circle-dollar-sign","category":"finance"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1icon"},"iconVariant":"neutral","iconSize":"m","title":"Revenue","subtitle":"Month to date","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"$48,200","subtext":"+8.1%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi1rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi1"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"active-users","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2icon"},"iconVariant":"neutral","iconSize":"m","title":"Active Users","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1,204","subtext":"+3.4%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi2rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi2"},{"type":"element","typeName":"SnippetCardItem","props":{"id":"churn","lhs":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"user-minus","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3icon"},"iconVariant":"neutral","iconSize":"m","title":"Churn","subtitle":"This month","bold":false,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3lhs"},"rhs":{"type":"element","typeName":"BoldText","props":{"variant":"number","value":"1.8%","subtext":"-0.3%","subtextVariant":"metric","size":"sm"},"partial":false,"hasDynamicProps":false,"statementId":"kpi3rhs"}},"partial":false,"hasDynamicProps":false,"statementId":"kpi3"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":false,"statementId":"kpiBlock"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Top Products","description":"By units sold"},"partial":false,"hasDynamicProps":false,"statementId":"productsHeader"},{"type":"element","typeName":"CompositeCardBlock","props":{"items":[{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-pro","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"package","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p1icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Pro","subtitle":"Best seller","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p1header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"2,410 units","subtext":"Sold this month","trend":{"direction":"up","value":12}},"partial":false,"hasDynamicProps":false,"statementId":"p1body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$29.00","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Pro"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true,"statementId":"p1btn"}}},"partial":false,"hasDynamicProps":true,"statementId":"p1"},{"type":"element","typeName":"CompositeCardItem","props":{"id":"widget-mini","header":{"type":"element","typeName":"IconText","props":{"icon":{"type":"element","typeName":"Icon","props":{"name":"box","category":"shopping"},"partial":false,"hasDynamicProps":false,"statementId":"p2icon"},"iconVariant":"neutral","iconSize":"m","title":"Widget Mini","subtitle":"New arrival","bold":true,"layout":"horizontal"},"partial":false,"hasDynamicProps":false,"statementId":"p2header"},"body":[{"type":"element","typeName":"MetricIndicatorInline","props":{"value":"980 units","subtext":"Sold this month","trend":{"direction":"up","value":4}},"partial":false,"hasDynamicProps":false,"statementId":"p2body"}],"footer":{"price":{"type":"element","typeName":"BoldText","props":{"variant":"text","value":"$14.00","subtextVariant":"text","size":"sm"},"partial":false,"hasDynamicProps":false},"button":{"type":"element","typeName":"Button","props":{"label":"View Details","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Show details for Widget Mini"}]}]}]},"variant":"secondary"},"partial":false,"hasDynamicProps":true,"statementId":"p2btn"}}},"partial":false,"hasDynamicProps":true,"statementId":"p2"}],"layout":"grid","responsive":true},"partial":false,"hasDynamicProps":true,"statementId":"productCards"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":29,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"openui-example-6","schema":"openui","input":"Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])","checkpoints":[{"at":142,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Te"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["editTable","formHeader","prefsForm"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":284,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text"}],"data":[]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["colRole","colStart","row1","row2","formHeader","prefsForm"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":426,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"en"}]}],"data":[]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["roleDesign","colStart","row1","row2","formHeader","prefsForm"],"orphaned":[],"statementCount":6,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":568,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Da"}],"data":[]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["row1","row2","formHeader","prefsForm"],"orphaned":[],"statementCount":8,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":710,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":false,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":false,"hasDynamicProps":false,"statementId":"editTable"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["formHeader","prefsForm"],"orphaned":[],"statementCount":10,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":852,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","fc2"],"orphaned":[],"statementCount":13,"errors":[{"code":"missing-required","component":"FormControl","path":"/input","message":"missing required field \"/input\" — signature: FormControl(label*: string, input*, hint: string)","statementId":"fc1"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":994,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","style2","fc2"],"orphaned":[],"statementCount":15,"errors":[{"code":"missing-required","component":"OptionCard","path":"/title","message":"missing required field \"/title\" — signature: OptionCard(value*: string, title*: string, subtitle: string, topContent, disabled: boolean)","statementId":"style1"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1136,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","fc2"],"orphaned":[],"statementCount":17,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1278,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":false,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":false,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":false,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["formButtons","toolChips"],"orphaned":[],"statementCount":19,"errors":[{"code":"null-required","component":"FormControl","path":"/input","message":"required field \"/input\" cannot be null — signature: FormControl(label*: string, input*, hint: string)","statementId":"fc2"},{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1420,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","tool2","tool3"],"orphaned":[],"statementCount":22,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1562,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":true,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":true,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":true,"hasDynamicProps":false,"statementId":"formHeader"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["formButtons","tool3"],"orphaned":[],"statementCount":25,"errors":[{"code":"null-required","component":"Form","path":"/buttons","message":"required field \"/buttons\" cannot be null — signature: Form(name*: string, buttons*: Buttons, fields*: array)","statementId":"prefsForm"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":1699,"expected":{"root":{"type":"element","typeName":"Stack","props":{"children":[{"type":"element","typeName":"InlineHeader","props":{"heading":"Team Roster","description":"Click a cell to edit"},"partial":false,"hasDynamicProps":false,"statementId":"tableHeader"},{"type":"element","typeName":"EditableTable","props":{"name":"roster","columns":[{"type":"text","key":"name","header":"Name"},{"type":"select","key":"role","header":"Role","options":[{"value":"eng","label":"Engineering"},{"value":"design","label":"Design"}]},{"type":"date-single","key":"start","header":"Start Date"}],"data":[{"id":"1","values":["Alex Kim","eng","2024-01-15"]},{"id":"2","values":["Jamie Lee","design","2024-03-02"]}]},"partial":false,"hasDynamicProps":false,"statementId":"editTable"},{"type":"element","typeName":"InlineHeader","props":{"heading":"Preferences","description":"Tell us how you like to work"},"partial":false,"hasDynamicProps":false,"statementId":"formHeader"},{"type":"element","typeName":"Form","props":{"name":"prefs","buttons":{"type":"element","typeName":"Buttons","props":{"buttons":[{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Save preferences"}]}]}]},"variant":"primary"},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"formButtons"},"fields":[{"type":"element","typeName":"FormControl","props":{"label":"Working Style","input":{"type":"element","typeName":"OptionCards","props":{"name":"style","type":"single","items":[{"type":"element","typeName":"OptionCard","props":{"value":"focused","title":"Deep Focus","subtitle":"Long uninterrupted blocks","topContent":{"type":"element","typeName":"Icon","props":{"name":"target","category":"tools"},"partial":false,"hasDynamicProps":false,"statementId":"style1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"style1"},{"type":"element","typeName":"OptionCard","props":{"value":"collab","title":"Collaborative","subtitle":"Frequent pairing and syncs","topContent":{"type":"element","typeName":"Icon","props":{"name":"users","category":"people"},"partial":false,"hasDynamicProps":false,"statementId":"style2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"style2"}]},"partial":false,"hasDynamicProps":false,"statementId":"styleCards"},"hint":"Pick the one that fits best"},"partial":false,"hasDynamicProps":false,"statementId":"fc1"},{"type":"element","typeName":"FormControl","props":{"label":"Tools","input":{"type":"element","typeName":"Chips","props":{"name":"tools","type":"multiple","items":[{"type":"element","typeName":"ChipItem","props":{"value":"figma","label":"Figma","icon":{"type":"element","typeName":"Icon","props":{"name":"figma","category":"design"},"partial":false,"hasDynamicProps":false,"statementId":"tool1icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool1"},{"type":"element","typeName":"ChipItem","props":{"value":"slack","label":"Slack","icon":{"type":"element","typeName":"Icon","props":{"name":"message-square","category":"communication"},"partial":false,"hasDynamicProps":false,"statementId":"tool2icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool2"},{"type":"element","typeName":"ChipItem","props":{"value":"notion","label":"Notion","icon":{"type":"element","typeName":"Icon","props":{"name":"notebook","category":"text"},"partial":false,"hasDynamicProps":false,"statementId":"tool3icon"}},"partial":false,"hasDynamicProps":false,"statementId":"tool3"}]},"partial":false,"hasDynamicProps":false,"statementId":"toolChips"},"hint":"Select all that apply"},"partial":false,"hasDynamicProps":false,"statementId":"fc2"}]},"partial":false,"hasDynamicProps":true,"statementId":"prefsForm"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":27,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"basic","schema":"test","input":"root = Card([t1, b1])\nt1 = Text(\"Hi\")\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Bu"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":true,"hasDynamicProps":false,"statementId":"t1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Button","path":"/label","message":"missing required field \"/label\" — signature: Button(label*: string, action, variant: \"primary\"|\"secondary\")","statementId":"b1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"Hi"},"partial":false,"hasDynamicProps":false,"statementId":"t1"},{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"missing-required","schema":"test","input":"root = Card([t1, b1])\nt1 = Text()\nb1 = Button(\"Go\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1","b1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex","b1"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["B"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Button"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":51,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Go"},"partial":false,"hasDynamicProps":false,"statementId":"b1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"null-required-with-default","schema":"test","input":"root = Card([t1])\nt1 = Text(null)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t1"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"t1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"required-default-fills","schema":"test","input":"root = Card([x])\nx = Tagged(1, true, \"x\", null)","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tag"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":null,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["nu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1,"flag":true,"kind":"x","tone":"neutral"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"unknown-component","schema":"test","input":"root = Card([Mystery(\"a\"), Text(\"b\")])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mys"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Mystery"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"Mystery","path":"","message":"Unknown component \"Mystery\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"excess-args","schema":"test","input":"root = Card([Text(\"a\", \"m\", \"extra\", 4)])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":41,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"excess-args","component":"Text","path":"","message":"Text takes 2 arg(s), got 4 (2 excess dropped)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"type-mismatch-scalar","schema":"test","input":"root = Card([Text(42)], 7)","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/text","message":"field \"/text\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/title","message":"field \"/title\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"enum-mismatch","schema":"test","input":"root = Card([Text(\"a\", \"xl\"), Button(\"b\", null, \"tertiary\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Button"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"terti"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"xl"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null,"variant":"tertiary"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"m"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Button","props":{"label":"b","action":null},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Text","path":"/size","message":"field \"/size\" expects one of [\"s\", \"m\", \"l\"] but got \"xl\"","statementId":"root"},{"code":"type-mismatch","component":"Button","path":"/variant","message":"field \"/variant\" expects one of [\"primary\", \"secondary\"] but got \"tertiary\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"enum-partial-deferred","schema":"test","input":"root = Card([Text(\"a\", \"x","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a","size":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"integer-boolean-const","schema":"test","input":"root = Card([x])\nx = Tagged(1.5, \"yes\", \"y\", \"loud\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["x"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tagg"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":{"k":"Member","obj":{"k":"Num","v":1},"field":"?"},"tone":"neutral"},"partial":true,"hasDynamicProps":true,"statementId":"x"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"neutral"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"kind":"y","tone":"loud"},"partial":true,"hasDynamicProps":false,"statementId":"x"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Tagged","props":{"count":1.5,"tone":"loud"},"partial":false,"hasDynamicProps":false,"statementId":"x"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Tagged","path":"/flag","message":"field \"/flag\" expects boolean but got string","statementId":"x"},{"code":"type-mismatch","component":"Tagged","path":"/kind","message":"field \"/kind\" expects one of [\"x\"] but got \"y\"","statementId":"x"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"nested-object","schema":"test","input":"root = Card([c1, c2, c3])\nc1 = Chart([\"a\"], [1], {unit: \"kg\"})\nc2 = Chart([\"a\"], [1], {scale: 2})\nc3 = Chart([\"a\"], [1], {unit: 5, scale: \"big\"})","checkpoints":[{"at":13,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":26,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c1","c2","c3"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c1"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":52,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"un":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":65,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c2","c3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":78,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":91,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scal":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"c2"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":104,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":117,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":130,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":143,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":true,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"scale":2}},"partial":true,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false,"statementId":"c3"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":145,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"kg"}},"partial":false,"hasDynamicProps":false,"statementId":"c1"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c2"},{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":false,"hasDynamicProps":false,"statementId":"c3"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Chart","path":"/meta/unit","message":"missing required field \"/meta/unit\"","statementId":"c2"},{"code":"type-mismatch","component":"Chart","path":"/meta/unit","message":"field \"/meta/unit\" expects string but got number","statementId":"c3"},{"code":"type-mismatch","component":"Chart","path":"/meta/scale","message":"field \"/meta/scale\" expects number but got string","statementId":"c3"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"array-items-pruned","schema":"test","input":"root = Card([Chart([\"a\", 2, \"c\"], [1, \"x\", 3])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","c"],"values":[1,3]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/1","message":"field \"/labels/1\" expects string but got number","statementId":"root"},{"code":"type-mismatch","component":"Chart","path":"/values/1","message":"field \"/values/1\" expects number but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"element-in-data-slot","schema":"test","input":"root = Card([Chart([Text(\"a\")], [1])])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"},{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":[],"values":[1]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Chart","path":"/labels/0","message":"field \"/labels/0\" expects string but got component \"Text\"","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"unresolved-and-orphaned","schema":"test","input":"root = Card([a, missing])\na = Text(\"x\")\nlonely = Text(\"y\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a","miss"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","missing"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":55,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":58,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["missing"],"orphaned":["lonely"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"cycle","schema":"test","input":"root = Card([a])\na = Card([b])\nb = Card([a])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"b"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"self-reference","schema":"test","input":"root = Card([root])","checkpoints":[{"at":2,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["r"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["roo"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["root"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"no-root-first-component","schema":"test","input":"x = 1\nmain = Card([Text(\"a\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["main"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"main"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":47,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"main"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["x","other"],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"root-name-statement","schema":"test","input":"Card = Card([Text(\"named\")])\nother = Card([])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"Card"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"n"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"named"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"Card"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["other"],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"duplicate-ids","schema":"test","input":"root = Card([a])\na = Text(\"first\")\na = Text(\"second\")","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fir"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"first"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":53,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"only-prose","schema":"test","input":"Here is your UI, it will appear below.","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"whitespace","schema":"test","input":" \n\t \n","checkpoints":[{"at":1,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":2,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":3,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":5,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":7,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"fences-and-prose","schema":"test","input":"Sure! Here it is:\n```openui\nroot = Card([a])\na = Text(\"fenced\")\n```\nAnything else?","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"f"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":82,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"fenced"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"multiple-fences","schema":"test","input":"```\nroot = Card([a])\n```\nand\n```\na = Text(\"second block\")\n```","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"secon"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second bloc"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":61,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"second block"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"unclosed-fence","schema":"test","input":"```openui\nroot = Card([a])\na = Text(\"str","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"a"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"str"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"fence-in-string","schema":"test","input":"root = Card([a])\na = Text(\"use ``` to fence\")","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"u"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use `"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` t"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fe"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"use ``` to fence"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"comments","schema":"test","input":"root = Card([a]) // trailing\n# full line\na = Text(\"not // a comment # here\")\n// done","checkpoints":[{"at":7,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":14,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not /"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a com"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment #"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":77,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"not // a comment # here"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"crlf","schema":"test","input":"root = Card([a])\r\na = Text(\"windows\")\r\n","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"wind"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":39,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"windows"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"string-escapes","schema":"test","input":"root = Card([a, b, c, d])\na = Text(\"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83d\\ude00\")\nb = Text('single \\' quote \\n esc \\q')\nc = Text(\"bad \\x escape\")\nd = Text(\"emoji 😀 and é and 漢字\")","checkpoints":[{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nqu"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ uni"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\\tnew\\nquote\\\" back\\\\ uni\\u00e9 pair\\ud83"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b","c","d"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te","c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":112,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' qu"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":128,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["c","d"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x"},"partial":true,"hasDynamicProps":false,"statementId":"c"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["d"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":160,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Te"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":176,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":true,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":true,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and"},"partial":true,"hasDynamicProps":false,"statementId":"d"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":187,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"tab\tnew\nquote\" back\\ unié pair😀"},"partial":false,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Text","props":{"text":"single ' quote \n esc q"},"partial":false,"hasDynamicProps":false,"statementId":"b"},{"type":"element","typeName":"Text","props":{"text":"bad \\x escape"},"partial":false,"hasDynamicProps":false,"statementId":"c"},{"type":"element","typeName":"Text","props":{"text":"emoji 😀 and é and 漢字"},"partial":false,"hasDynamicProps":false,"statementId":"d"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"emoji-outside-strings","schema":"test","input":"root = Card([a]) 😀\na = Text(\"ok\") ✅","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":19,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":33,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"unterminated-string","schema":"test","input":"root = Card([a])\na = Text(\"streaming tex","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"s"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"strea"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"streaming tex"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"unterminated-escape","schema":"test","input":"root = Card([a])\na = Text(\"ends with \\","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"ends with \\"},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"numbers","schema":"test","input":"root = Card([Chart([\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"], [-3, 1.5, 1e3, 007, -0, 2.5e-3])])\n$x = 1e\n$y = 1E+2\n$z = 3.","checkpoints":[{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Chart"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":63,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,0]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,{"k":"Member","obj":{"k":"Num","v":2},"field":"?"},null]},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":81,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$x":null},"queryStatements":[],"mutationStatements":[]}},{"at":99,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$x":null,"$y":100},"queryStatements":[],"mutationStatements":[]}},{"at":106,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a","b","c","d","e","f"],"values":[-3,1.5,1000,7,0,0.0025]},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$x":null,"$y":100,"$z":{"k":"Member","obj":{"k":"Num","v":3},"field":"?"}},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"operators","schema":"test","input":"$a = 1\n$b = \"2\"\nroot = Card([Text($a + $b * 2 - -1 > 3 && !$c || $a == \"1\" ? \"yes\" : \"no\")])","checkpoints":[{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$a":1},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":56,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2"},"queryStatements":[],"mutationStatements":[]}},{"at":64,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":""}}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"ye"},"else":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":88,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}},{"at":92,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"BinOp","op":"||","left":{"k":"BinOp","op":"&&","left":{"k":"BinOp","op":">","left":{"k":"BinOp","op":"-","left":{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$a"},"right":{"k":"BinOp","op":"*","left":{"k":"StateRef","n":"$b"},"right":{"k":"Num","v":2}}},"right":{"k":"Num","v":-1}},"right":{"k":"Num","v":3}},"right":{"k":"UnaryOp","op":"!","operand":{"k":"StateRef","n":"$c"}}},"right":{"k":"BinOp","op":"==","left":{"k":"StateRef","n":"$a"},"right":{"k":"Str","v":"1"}}},"then":{"k":"Str","v":"yes"},"else":{"k":"Str","v":"no"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$a":1,"$b":"2","$c":null},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"multiline-ternary","schema":"test","input":"$on = true\nroot = Card([t])\nt = Text($on\n ? \"enabled\"\n : \"disabled\")","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Text"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"StateRef","n":"$on"}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"en"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Null"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabl"}}},"partial":true,"hasDynamicProps":true,"statementId":"t"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Ternary","cond":{"k":"StateRef","n":"$on"},"then":{"k":"Str","v":"enabled"},"else":{"k":"Str","v":"disabled"}}},"partial":false,"hasDynamicProps":true,"statementId":"t"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$on":true},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"member-index","schema":"test","input":"$data = {rows: [{name: \"a\"}, {name: \"b\"}], \"key x\": 1}\nroot = Card([Text($data.rows[1].name), Text($data.rows.name), Text($data[\"key x\"])])","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"row":null}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":""}]}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":null,"?":null}]}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key":null}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"row"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}},{"at":139,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Index","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"index":{"k":"Num","v":1}},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"StateRef","n":"$data"},"field":"rows"},"field":"name"}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Index","obj":{"k":"StateRef","n":"$data"},"index":{"k":"Str","v":"key x"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$data":{"rows":[{"name":"a"},{"name":"b"}],"key x":1}},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"builtins","schema":"test","input":"$items = [3, 1, 2]\nroot = Card([Text(\"\" + @Count($items)), Text(\"\" + @Sum($items)), Text(@Round(2.555, 2) + \"\")])\nbare = Count($items)","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3]},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Text"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Count"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Count"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Ph","n":"Su"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Su"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"Comp","name":"Round","args":[]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Null"}},"size":null},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}},{"at":134,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Count","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Str","v":""},"right":{"k":"Comp","name":"Sum","args":[{"k":"StateRef","n":"$items"}]}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Comp","name":"Round","args":[{"k":"Num","v":2.555},{"k":"Num","v":2}]},"right":{"k":"Str","v":""}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":["bare"],"statementCount":3,"errors":[]},"stateDeclarations":{"$items":[3,1,2]},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"actions","schema":"test","input":"$n = 0\nroot = Card([b1, b2, b3])\nb1 = Button(\"Inc\", Action([@Set($n, $n + 1), @ToAssistant(\"Bumped\", \"ctx\")]))\nb2 = Button(\"Reset\", Action([@Reset($n)]))\nb3 = Button(\"Docs\", Action([@OpenUrl(\"https://openui.com\")]))","checkpoints":[{"at":18,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Card"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b1","b2","b3"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b1"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Ac","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Ph","n":"ToAssistant"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["ToAssistant","b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b2","b3"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":126,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Re"},"partial":true,"hasDynamicProps":false,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":144,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Ph","n":"Res"}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Res","b3"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":162,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["But"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":180,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":null},"partial":true,"hasDynamicProps":false,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Action"],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":198,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https:"}]}]}]}},"partial":true,"hasDynamicProps":true,"statementId":"b3"}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}},{"at":215,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Button","props":{"label":"Inc","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Set","args":[{"k":"StateRef","n":"$n"},{"k":"BinOp","op":"+","left":{"k":"StateRef","n":"$n"},"right":{"k":"Num","v":1}}]},{"k":"Comp","name":"ToAssistant","args":[{"k":"Str","v":"Bumped"},{"k":"Str","v":"ctx"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b1"},{"type":"element","typeName":"Button","props":{"label":"Reset","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Reset","args":[{"k":"StateRef","n":"$n"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b2"},{"type":"element","typeName":"Button","props":{"label":"Docs","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"OpenUrl","args":[{"k":"Str","v":"https://openui.com"}]}]}]}},"partial":false,"hasDynamicProps":true,"statementId":"b3"}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":5,"errors":[]},"stateDeclarations":{"$n":0},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"each","schema":"test","input":"$todos = [{title: \"a\", done: false}, {title: \"b\", done: true}]\nroot = Card(@Each($todos, todo, Text(todo.title)))","checkpoints":[{"at":10,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[]},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a"}]},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["f","f"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"ti":null,"?":null}]},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b"}]},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":70,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":80,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["Each"],"orphaned":[],"statementCount":2,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":90,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ph","n":"t"}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":100,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[],"mappedProps":{}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":110,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}},{"at":113,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":{"k":"Comp","name":"Each","args":[{"k":"StateRef","n":"$todos"},{"k":"Ref","n":"todo"},{"k":"Comp","name":"Text","args":[{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}],"mappedProps":{"text":{"k":"Member","obj":{"k":"Ref","n":"todo"},"field":"title"}}}]}},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$todos":[{"title":"a","done":false},{"title":"b","done":true}]},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"query-mutation","schema":"test","input":"$q = \"x\"\nusers = Query(\"list_users\", {search: $q, page: $page}, {rows: []}, 30)\nsave = Mutation(\"save_user\", {name: $q})\nroot = Card([Text(users.rows.length + \" users\"), Button(\"Save\", Action([@Run(save), @Run(users)]))])","checkpoints":[{"at":19,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["users"],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[],"mutationStatements":[]}},{"at":38,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":57,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x"},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"Null"}],["?",{"k":"Null"}]]},"defaultsAST":null,"refreshAST":null,"deps":["$q"],"complete":true}],"mutationStatements":[]}},{"at":76,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":null,"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":95,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":["save"],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[]}},{"at":114,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"Null"}],["?",{"k":"Null"}]]}}]}},{"at":133,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":152,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"le"}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":171,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["B"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":190,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":null},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Actio"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":209,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":true,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Ph","n":"Run"}]}]}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Run"],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}},{"at":221,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":{"k":"BinOp","op":"+","left":{"k":"Member","obj":{"k":"Member","obj":{"k":"RuntimeRef","n":"users","refType":"query"},"field":"rows"},"field":"length"},"right":{"k":"Str","v":" users"}}},"partial":false,"hasDynamicProps":true},{"type":"element","typeName":"Button","props":{"label":"Save","action":{"k":"Comp","name":"Action","args":[{"k":"Arr","els":[{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"save","refType":"mutation"}]},{"k":"Comp","name":"Run","args":[{"k":"RuntimeRef","n":"users","refType":"query"}]}]}]}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":4,"errors":[]},"stateDeclarations":{"$q":"x","$page":null},"queryStatements":[{"statementId":"users","toolAST":{"k":"Str","v":"list_users"},"argsAST":{"k":"Obj","entries":[["search",{"k":"StateRef","n":"$q"}],["page",{"k":"StateRef","n":"$page"}]]},"defaultsAST":{"k":"Obj","entries":[["rows",{"k":"Arr","els":[]}]]},"refreshAST":{"k":"Num","v":30},"deps":["$q","$page"],"complete":true}],"mutationStatements":[{"statementId":"save","toolAST":{"k":"Str","v":"save_user"},"argsAST":{"k":"Obj","entries":[["name",{"k":"StateRef","n":"$q"}]]}}]}}]}, +{"name":"state-query","schema":"test","input":"$data = Query(\"get\", {})\nroot = Card([Text(\"x\")])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Qu","Qu"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$data":null},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":""},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":null,"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":25,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"$data"}]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":35,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[{"statementId":"$data","toolAST":{"k":"Str","v":"get"},"argsAST":{"k":"Obj","entries":[]},"defaultsAST":null,"refreshAST":null,"complete":true}],"mutationStatements":[]}}]}, +{"name":"inline-query","schema":"test","input":"root = Card([Text(Query(\"get\", {}))])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Qu"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":37,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"inline-reserved","component":"Query","path":"","message":"Query() must be declared as a top-level statement, not used inline as a value","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"assignment","schema":"test","input":"$v = \"\"\nroot = Card([Input(\"name\", $v = $value)])","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Inpu"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"na"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"Null"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"excess-args","component":"Input","path":"","message":"Input takes 2 arg(s), got 3 (1 excess dropped)","statementId":"root"}]},"stateDeclarations":{"$v":""},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$valu"}}},"partial":true,"hasDynamicProps":true}]},"partial":true,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$valu":null},"queryStatements":[],"mutationStatements":[]}},{"at":49,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Input","props":{"name":"name","value":{"k":"Assign","target":"$v","value":{"k":"StateRef","n":"$value"}}},"partial":false,"hasDynamicProps":true}]},"partial":false,"hasDynamicProps":true,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$v":"","$value":null},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"object-key-order","schema":"test","input":"$o = {b: 1, 2: \"two\", a: 3, 1: \"one\", \"10\": 10}\nroot = Card([Text(\"x\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{}},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"tw","b":1}},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"2":"two","b":1,"a":null}},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":null,"2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":null,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"x"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{"$o":{"1":"one","2":"two","10":10,"b":1,"a":3}},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"missing-commas","schema":"test","input":"root = Card([Text(\"a\") Text(\"b\"), Text(\"c\"),])","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":46,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"b"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"c"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"lowercase-builtin-name","schema":"test","input":"root = Card([Text(@first([1]))])","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Ca"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Te"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["fi"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["first"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"unknown-component","component":"first","path":"","message":"Unknown component \"first\" — not found in catalog or builtins. Available components: Card, Text, Button, Input, Chart, Tagged","statementId":"root"},{"code":"null-required","component":"Text","path":"/text","message":"required field \"/text\" cannot be null — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"unknown-tokens","schema":"test","input":"root = Card([Text(\"a\")]) ; ~ ^\n$ = 3\n= 4\nfoo","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Tex"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":44,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"a"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"combining-characters","schema":"test","input":"root = Card([Text(\"e\\u0301 cafe\\u0301\"), Text(\"한국어\"), Text(\"ok\")])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u03"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é caf"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"e\\u0301 cafe\\u030"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["T"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":true,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"é café"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"한국어"},"partial":false,"hasDynamicProps":false},{"type":"element","typeName":"Text","props":{"text":"ok"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"truncated-mid-call","schema":"test","input":"root = Card([a, b])\na = Text(\"one\")\nb = Button(\"tw","checkpoints":[{"at":5,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":10,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Car"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["a"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["a","b"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":25,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["T","b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":""},"partial":true,"hasDynamicProps":false,"statementId":"a"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":35,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["b"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":45,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":false,"hasDynamicProps":false,"statementId":"a"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Butto"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":50,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"one"},"partial":true,"hasDynamicProps":false,"statementId":"a"},{"type":"element","typeName":"Button","props":{"label":"tw"},"partial":true,"hasDynamicProps":false,"statementId":"b"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"truncated-mid-object","schema":"test","input":"root = Card([Chart([\"a\"], [1], {unit: \"k","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["Cha"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Chart","path":"/values","message":"missing required field \"/values\" — signature: Chart(labels*: array, values*: array, meta: object)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1]},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":null,"?":null}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Chart","props":{"labels":["a"],"values":[1],"meta":{"unit":"k"}},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"data-in-component-slot","schema":"test","input":"root = Card([Text(\"hi\"), { text: \"a\" }, \"b\", 3, [Text(\"x\")], true])","checkpoints":[{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":30,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":54,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Text","path":"/text","message":"missing required field \"/text\" — signature: Text(text*: string, size: \"s\"|\"m\"|\"l\")","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":66,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":true,"hasDynamicProps":false}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/5","message":"field \"/children/5\" expects Text | Button | Chart but got boolean","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":67,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"Text","props":{"text":"hi"},"partial":false,"hasDynamicProps":false}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/1","message":"field \"/children/1\" expects Text | Button | Chart but got plain object","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/2","message":"field \"/children/2\" expects Text | Button | Chart but got string","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/3","message":"field \"/children/3\" expects Text | Button | Chart but got number","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/4","message":"field \"/children/4\" expects Text | Button | Chart but got array","statementId":"root"},{"code":"type-mismatch","component":"Card","path":"/children/5","message":"field \"/children/5\" expects Text | Button | Chart but got boolean","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"data-in-component-slot-via-ref","schema":"test","input":"root = Card(items)\nitems = [{ text: \"a\" }]","checkpoints":[{"at":4,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":8,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["C"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Card","path":"/children","message":"missing required field \"/children\" — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":16,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":["item"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":20,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["items"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["items"],"orphaned":[],"statementCount":1,"errors":[{"code":"null-required","component":"Card","path":"/children","message":"required field \"/children\" cannot be null — signature: Card(children*: array, title: string)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":28,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":32,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":40,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":42,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":2,"errors":[{"code":"type-mismatch","component":"Card","path":"/children/0","message":"field \"/children/0\" expects Text | Button | Chart but got plain object","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"hoisted-data-def","schema":"hoisted","input":"root = Tree({ label: \"a\" })","checkpoints":[{"at":3,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":6,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":9,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":["Tr"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":12,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[{"code":"missing-required","component":"Tree","path":"/node","message":"missing required field \"/node\" — signature: Tree(node*: __schema0)","statementId":"root"}]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":15,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"l":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":18,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"labe":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":21,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":null,"?":null}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":"a"}},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":27,"expected":{"root":{"type":"element","typeName":"Tree","props":{"node":{"label":"a"}},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]}, +{"name":"cloud-envelope","schema":"chat","input":"]]>openui:content?thesys=true\n```openui-lang\nroot = Card([h, t])\nh = CardHeader(\"Q3\", \"Revenue\")\nt = TextContent(\"Up 12%\")\n```\n]]>openui:end","checkpoints":[{"at":12,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":24,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":36,"expected":{"root":null,"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":48,"expected":{"root":null,"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":0,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":60,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["h"],"orphaned":[],"statementCount":1,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":72,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["Car","t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":84,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3"},"partial":true,"hasDynamicProps":false,"statementId":"h"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":96,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["t"],"orphaned":[],"statementCount":2,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":108,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":["TextCon"],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":120,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":true,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":true,"hasDynamicProps":false,"statementId":"t"}]},"partial":true,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":true,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":132,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}},{"at":140,"expected":{"root":{"type":"element","typeName":"Card","props":{"children":[{"type":"element","typeName":"CardHeader","props":{"title":"Q3","subtitle":"Revenue"},"partial":false,"hasDynamicProps":false,"statementId":"h"},{"type":"element","typeName":"TextContent","props":{"text":"Up 12%"},"partial":false,"hasDynamicProps":false,"statementId":"t"}]},"partial":false,"hasDynamicProps":false,"statementId":"root"},"meta":{"incomplete":false,"unresolved":[],"orphaned":[],"statementCount":3,"errors":[]},"stateDeclarations":{},"queryStatements":[],"mutationStatements":[]}}]} +] diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chart-formats.json b/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chart-formats.json index b2b2c2c559..2a216c4032 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chart-formats.json +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chart-formats.json @@ -1,147 +1,31 @@ [ - { - "value": 0, - "tick": "0", - "tooltip": "0" - }, - { - "value": 1, - "tick": "1", - "tooltip": "1" - }, - { - "value": -1, - "tick": "-1", - "tooltip": "-1" - }, - { - "value": 7, - "tick": "7", - "tooltip": "7" - }, - { - "value": 0.5, - "tick": "0.50", - "tooltip": "0.5" - }, - { - "value": 0.125, - "tick": "0.13", - "tooltip": "0.125" - }, - { - "value": 1.005, - "tick": "1.00", - "tooltip": "1.005" - }, - { - "value": 1.25, - "tick": "1.25", - "tooltip": "1.25" - }, - { - "value": 12.345, - "tick": "12.35", - "tooltip": "12.345" - }, - { - "value": -0.04, - "tick": "-0.04", - "tooltip": "-0.04" - }, - { - "value": 0.005, - "tick": "0.01", - "tooltip": "0.005" - }, - { - "value": 999, - "tick": "999", - "tooltip": "999" - }, - { - "value": 999.99, - "tick": "999.99", - "tooltip": "999.99" - }, - { - "value": 1000, - "tick": "1.0K", - "tooltip": "1,000" - }, - { - "value": 1250, - "tick": "1.3K", - "tooltip": "1,250" - }, - { - "value": 9999, - "tick": "10.0K", - "tooltip": "9,999" - }, - { - "value": 10000, - "tick": "10K", - "tooltip": "10,000" - }, - { - "value": 15500, - "tick": "16K", - "tooltip": "15,500" - }, - { - "value": -2500, - "tick": "-2.5K", - "tooltip": "-2,500" - }, - { - "value": 99999.5, - "tick": "100K", - "tooltip": "99,999.5" - }, - { - "value": 100000, - "tick": "100K", - "tooltip": "100K" - }, - { - "value": 123456, - "tick": "123K", - "tooltip": "123.4K" - }, - { - "value": 999999, - "tick": "1000K", - "tooltip": "999.9K" - }, - { - "value": 1234567, - "tick": "1.2M", - "tooltip": "1.2M" - }, - { - "value": -7654321, - "tick": "-7.7M", - "tooltip": "-7.6M" - }, - { - "value": 2500000000, - "tick": "2.5B", - "tooltip": "2.5B" - }, - { - "value": 1000000000000, - "tick": "1.0T", - "tooltip": "1T" - }, - { - "value": 15000000000000, - "tick": "15T", - "tooltip": "15T" - }, - { - "value": 1.23456, - "tick": "1.23", - "tooltip": "1.235" - } +{"value":0,"tick":"0","tooltip":"0"}, +{"value":1,"tick":"1","tooltip":"1"}, +{"value":-1,"tick":"-1","tooltip":"-1"}, +{"value":7,"tick":"7","tooltip":"7"}, +{"value":0.5,"tick":"0.50","tooltip":"0.5"}, +{"value":0.125,"tick":"0.13","tooltip":"0.125"}, +{"value":1.005,"tick":"1.00","tooltip":"1.005"}, +{"value":1.25,"tick":"1.25","tooltip":"1.25"}, +{"value":12.345,"tick":"12.35","tooltip":"12.345"}, +{"value":-0.04,"tick":"-0.04","tooltip":"-0.04"}, +{"value":0.005,"tick":"0.01","tooltip":"0.005"}, +{"value":999,"tick":"999","tooltip":"999"}, +{"value":999.99,"tick":"999.99","tooltip":"999.99"}, +{"value":1000,"tick":"1.0K","tooltip":"1,000"}, +{"value":1250,"tick":"1.3K","tooltip":"1,250"}, +{"value":9999,"tick":"10.0K","tooltip":"9,999"}, +{"value":10000,"tick":"10K","tooltip":"10,000"}, +{"value":15500,"tick":"16K","tooltip":"15,500"}, +{"value":-2500,"tick":"-2.5K","tooltip":"-2,500"}, +{"value":99999.5,"tick":"100K","tooltip":"99,999.5"}, +{"value":100000,"tick":"100K","tooltip":"100K"}, +{"value":123456,"tick":"123K","tooltip":"123.4K"}, +{"value":999999,"tick":"1000K","tooltip":"999.9K"}, +{"value":1234567,"tick":"1.2M","tooltip":"1.2M"}, +{"value":-7654321,"tick":"-7.7M","tooltip":"-7.6M"}, +{"value":2500000000,"tick":"2.5B","tooltip":"2.5B"}, +{"value":1000000000000,"tick":"1.0T","tooltip":"1T"}, +{"value":15000000000000,"tick":"15T","tooltip":"15T"}, +{"value":1.23456,"tick":"1.23","tooltip":"1.235"} ] diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chat-examples.json b/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chat-examples.json index e860788f0f..35802c93cc 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chat-examples.json +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/chat-examples.json @@ -1,22 +1,7 @@ [ - { - "name": "chat-example-1", - "input": "Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }" - }, - { - "name": "chat-example-2", - "input": "Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")" - }, - { - "name": "chat-example-3", - "input": "Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)" - }, - { - "name": "chat-example-4", - "input": "Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }" - }, - { - "name": "chat-example-5", - "input": "Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")" - } +{"name":"chat-example-1","input":"Example 1 — Informational response (the shape for \"tell me about X\" / explainer asks):\n\nroot = Card([header, intro, highlights, statsHeader, statsCards, sectionsBlock, actionBtns], [src1, src2])\nheader = CardHeader(\"Paris\", \"The City of Light · France's Eternal Capital\")\nintro = TextContent(\"Paris is one of the world's most visited cities — a timeless blend of iconic landmarks, world-class cuisine, art, and romance [1]. In 2026 the city is buzzing with new energy: the **Grand Palais** has reopened after a €466M renovation, and you can now **swim in the Seine** for the first time in over a century [2].\")\nhighlights = ContextCardBlock([h1, h2, h3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this aspect of Paris\" })\nh1 = ContextCardItem(\"art-museums\", \"Art & Museums\", \"143 museums including the Louvre & newly reopened Grand Palais.\", \"gray\", \"https://cdn.britannica.com/03/121003-050-2544BD4E/Interior-Louvre-Museum-Paris.jpg\")\nh2 = ContextCardItem(\"gastronomy\", \"Gastronomy\", \"9,000+ restaurants, 130+ Michelin stars, and the world's best baguettes.\", \"gray\")\nh3 = ContextCardItem(\"fashion-capital\", \"Fashion Capital\", \"Home to Chanel, Dior, Louis Vuitton & Hermès — the global luxury hub.\", \"gray\", \"https://thumbs.dreamstime.com/z/dior-storefront-facade-chanel-store-lvmh-s-french-designer-modehouse-christian-adjacent-to-luxury-fashion-beauty-brand-327161553.jpg\")\nstatsHeader = InlineHeader(\"Paris by the Numbers\", \"Key visitor statistics\")\nstatsCards = OverviewCardBlock([ov1, ov2, ov3], \"grid\", true)\nov1 = OverviewCardItem(\"annual-visitors\", ov1top, ov1metric)\nov1top = IconText(ov1icon, \"neutral\", \"m\", \"Annual Visitors\", \"2024 arrivals\", false, \"vertical\")\nov1icon = Icon(\"users\", \"people\")\nov1metric = MetricIndicatorInline(\"48.7M\", \"tourists\", { direction: \"up\", value: 2.5 })\nov2 = OverviewCardItem(\"museums-monuments\", ov2top, ov2metric)\nov2top = IconText(ov2icon, \"neutral\", \"m\", \"Museums & Monuments\", \"Cultural sites\", false, \"vertical\")\nov2icon = Icon(\"landmark\", \"buildings\")\nov2metric = MetricIndicatorInline(\"2,370+\", \"across the city\")\nov3 = OverviewCardItem(\"tourism-revenue\", ov3top, ov3metric)\nov3top = IconText(ov3icon, \"neutral\", \"m\", \"Tourism Revenue\", \"2024 estimate\", false, \"vertical\")\nov3icon = Icon(\"circle-dollar-sign\", \"finance\")\nov3metric = MetricIndicatorInline(\"€23.4B\", \"generated\")\nsectionsBlock = SectionBlock([secLandmarks, secFood, secWhen], false)\nsecLandmarks = SectionItem(\"landmarks\", \"Iconic Landmarks\", [landmarksCarousel])\nlandmarksCarousel = VisualCardBlock([lm1, lm2, lm3, lm4], \"carousel\", true, { type: \"continue_conversation\", context: \"Tell me more about this Paris landmark\" })\nlm1 = VisualCardItem(lm1body, \"eiffel-tower\", \"https://c8.alamy.com/comp/RYEB13/aerial-view-of-the-eiffel-tower-with-the-park-champ-de-mars-and-the-river-seine-paris-france-RYEB13.jpg\", lm1tag, \"Aerial view of the Eiffel Tower\")\nlm1body = BoldText(\"text\", \"Eiffel Tower\", \"Open daily 9am–midnight\")\nlm1tag = Tag(\"Must-See\", lm1tagIcon, \"sm\", \"info\")\nlm1tagIcon = Icon(\"star\", \"shapes\")\nlm2 = VisualCardItem(lm2body, \"the-louvre\", \"https://images.fineartamerica.com/images/artworkimages/mediumlarge/3/1-exterior-of-musee-du-louvre-museum-paris-france-bernard-jaubert.jpg\", lm2tag, \"Exterior of the Louvre museum\")\nlm2body = BoldText(\"text\", \"The Louvre\", \"World's largest art museum\")\nlm2tag = Tag(\"8.9M visits/yr\", lm2tagIcon, \"sm\", \"success\")\nlm2tagIcon = Icon(\"trending-up\", \"charts\")\nlm3 = VisualCardItem(lm3body, \"notre-dame\", \"https://cdn.britannica.com/29/255529-050-63A22A3C/notre-dame-de-paris-cathedral-paris-france.jpg\", lm3tag, \"Notre-Dame cathedral facade\")\nlm3body = BoldText(\"text\", \"Notre-Dame\", \"Fully restored cathedral\")\nlm3tag = Tag(\"Reopened 2024\", lm3tagIcon, \"sm\", \"warning\")\nlm3tagIcon = Icon(\"hammer\", \"tools\")\nlm4 = VisualCardItem(lm4body, \"versailles\", \"https://cdn.britannica.com/76/130076-050-31128A3D/Latona-Fountain-Balthazard-Marsy-Gaspard-Andre-Le.jpg\", lm4tag, \"Latona Fountain at Versailles\")\nlm4body = BoldText(\"text\", \"Palace of Versailles\", \"Royal gardens & grand halls\")\nlm4tag = Tag(\"Day Trip\", lm4tagIcon, \"sm\", \"neutral\")\nlm4tagIcon = Icon(\"train-front\", \"travel\")\nsecFood = SectionItem(\"food\", \"Food & Drink\", [foodCards])\nfoodCards = ContextCardBlock([f1, f2, f3], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about eating and drinking in Paris\" })\nf1 = ContextCardItem(\"bistros\", \"Bistros\", \"Classic French fare — try Les Arlots for confit beef cheeks.\", \"gray\", \"https://everydayparisian.com/wp-content/uploads/2023/01/IMG_0221-768x1024.webp\")\nf2 = ContextCardItem(\"fine-dining\", \"Fine Dining\", \"Septime leads a new wave of creative Michelin-starred cuisine.\", \"gray\", \"https://production-data.worldofmouth.app/images/72b2e6db-97ea-49c4-aa5d-3b7c8121c812.jpg\")\nf3 = ContextCardItem(\"bakeries\", \"Bakeries\", \"Shinya Pain for sourdough. Grand Prix-winning baguettes citywide.\", \"gray\", \"https://www.davidlebovitz.com/wp-content/uploads/2018/09/Le-petit-grain-paris-bakery-boulangerie-patisserie-pastry-shop-8-640x895.jpg\")\nsecWhen = SectionItem(\"when\", \"Best Time to Visit\", [whenTabs])\nwhenTabs = Tabs([tabSpring, tabSummer])\ntabSpring = TabItem(\"spring\", \"Spring\", [springList])\nspringList = ListBlock([sp1, sp2, sp3], \"number\")\nsp1 = ListItem(\"Cherry blossoms at Parc de Sceaux\", \"March – May\", null, null, { type: \"continue_conversation\", context: \"Tell me about cherry blossom season in Paris\" })\nsp2 = ListItem(\"Picnics along the Seine & in city parks\", \"Warm, lively atmosphere\", null, null, { type: \"continue_conversation\", context: \"Where are the best picnic spots in Paris?\" })\nsp3 = ListItem(\"Fewer crowds than summer\", \"Ideal for sightseeing\", null, null, { type: \"continue_conversation\", context: \"How busy is Paris in spring?\" })\ntabSummer = TabItem(\"summer\", \"Summer\", [summerList])\nsummerList = ListBlock([su1, su2, su3], \"number\")\nsu1 = ListItem(\"Swim in the Seine — open July & August 2026\", \"First time in 102 years\", null, null, { type: \"continue_conversation\", context: \"Tell me about swimming in the Seine\" })\nsu2 = ListItem(\"Open-air cinema at Parc de la Villette\", \"Free films under the stars\", null, null, { type: \"continue_conversation\", context: \"Tell me about the open-air cinema at Parc de la Villette\" })\nsu3 = ListItem(\"Bastille Day celebrations on July 14\", \"Fireworks at the Eiffel Tower\", null, null, { type: \"continue_conversation\", context: \"What happens in Paris on Bastille Day?\" })\nactionBtns = Buttons([btn1, btn2, btn3], \"row\")\nbtn1 = Button(\"Plan a Trip to Paris\", { type: \"continue_conversation\", context: \"Help me plan a trip to Paris\" }, \"primary\")\nbtn2 = Button(\"Best Hotels in Paris\", { type: \"continue_conversation\", context: \"Show me the best hotels in Paris\" }, \"secondary\")\nbtn3 = Button(\"Build a Paris Itinerary\", { type: \"continue_conversation\", context: \"Build a 5-day Paris itinerary for me\" }, \"secondary\")\nsrc1 = { title: \"Paris Travel Guide 2025\", sourceName: \"Travel and Tour World\", url: \"https://www.travelandtourworld.com/news/article/from-iconic-landmarks-to-hidden-gems-the-ultimate-paris-travel-guide-for-2025-you-need-to-read-now/\" }\nsrc2 = { title: \"Best Things to Do in Paris 2026\", sourceName: \"Time Out Paris\", url: \"http://www.timeout.fr/paris/en/for-tourists\" }"}, +{"name":"chat-example-2","input":"Example 2 — Data and analytics response (quantitative asks lead with KPIs and charts):\n\nroot = Card([pageHeader, kpiBlock, sections, deepDiveHeader, compositeCards, actionButtons])\npageHeader = CardHeader(\"Analytics Dashboard\", \"April 2026 · Business Performance Overview\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3, kpi4], \"grid\", true)\nkpi1 = SnippetCardItem(\"total-revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Total Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$284,500\", \"+12.4%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"Monthly active users\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"47,320\", \"+6.8%\", \"metric\")\nkpi3 = SnippetCardItem(\"conversion-rate\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Conversion Rate\", \"Avg. this month\", false, \"horizontal\")\nkpi3icon = Icon(\"trending-up\", \"charts\")\nkpi3rhs = BoldText(\"number\", \"5.7%\", \"+0.9%\", \"metric\")\nkpi4 = SnippetCardItem(\"churn-rate\", kpi4lhs, kpi4rhs)\nkpi4lhs = IconText(kpi4icon, \"neutral\", \"m\", \"Churn Rate\", \"Monthly customer churn\", false, \"horizontal\")\nkpi4icon = Icon(\"user-minus\", \"people\")\nkpi4rhs = BoldText(\"number\", \"2.1%\", \"-0.4%\", \"metric\")\nsections = SectionBlock([secUsers, secChannels], false)\nsecUsers = SectionItem(\"users\", \"User Activity\", [userTabs])\nuserTabs = Tabs([tabGrowth, tabRetention])\ntabGrowth = TabItem(\"growth\", \"User Growth\", [growthChart])\ngrowthChart = LineChart(months, [dauSeries, mauSeries], \"natural\", \"Month\", \"Users (k)\")\nmonths = [\"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\", \"Jan\", \"Feb\", \"Mar\", \"Apr\"]\ndauSeries = Series(\"DAU\", [5.1, 5.4, 5.8, 6.2, 6.7, 7.1, 7.6, 8.0, 8.4, 8.9, 9.3, 9.8])\nmauSeries = Series(\"MAU\", [28.4, 30.1, 31.8, 33.5, 35.2, 37.1, 38.8, 40.4, 42.1, 43.9, 45.6, 47.3])\ntabRetention = TabItem(\"retention\", \"Cohort Retention\", [retentionChart])\nretentionChart = LineChart(cohortMonths, [cohortJan, cohortFeb, cohortMar], \"natural\", \"Month Since Signup\", \"Retention (%)\")\ncohortMonths = [\"Month 0\", \"Month 1\", \"Month 2\", \"Month 3\", \"Month 4\", \"Month 5\", \"Month 6\"]\ncohortJan = Series(\"Jan Cohort\", [100, 80, 70, 62, 56, 51, 47])\ncohortFeb = Series(\"Feb Cohort\", [100, 83, 73, 65, 59, 54, 50])\ncohortMar = Series(\"Mar Cohort\", [100, 86, 76, 68, 62, 0, 0])\nsecChannels = SectionItem(\"channels\", \"Acquisition Channels\", [channelTabs])\nchannelTabs = Tabs([tabChannelBar, tabChannelTable])\ntabChannelBar = TabItem(\"channel-bar\", \"Revenue by Channel\", [channelBarChart])\nchannelBarChart = HorizontalBarChart(channels, [channelSeries], \"grouped\", \"Revenue ($k)\", \"Channel\")\nchannels = [\"Organic Search\", \"Paid Ads\", \"Referral Program\", \"Partner Network\", \"Direct / Brand\", \"Email Campaigns\"]\nchannelSeries = Series(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4])\ntabChannelTable = TabItem(\"channel-table\", \"Full Breakdown\", [channelTable])\nchannelTable = Table([colChannel, colLeads, colConv, colCac, colRevenue, colStatus])\ncolChannel = Col(\"Channel\", channels, \"string\")\ncolLeads = Col(\"Leads\", [4210, 3180, 2050, 1120, 1290, 820], \"number\")\ncolConv = Col(\"Conv. Rate\", [\"6.4%\", \"5.1%\", \"9.4%\", \"11.8%\", \"5.8%\", \"8.1%\"], \"string\")\ncolCac = Col(\"CAC ($)\", [188, 395, 132, 109, 218, 154], \"number\")\ncolRevenue = Col(\"Revenue ($k)\", [82.4, 68.1, 54.6, 38.2, 26.8, 14.4], \"number\")\ncolStatus = Col(\"Status\", [\"Scaling\", \"Optimizing\", \"Scaling\", \"Growing\", \"Stable\", \"Stable\"], \"string\")\ndeepDiveHeader = InlineHeader(\"Support Health & Marketing ROI\", \"Click a card to explore deeper insights\")\ncompositeCards = CompositeCardBlock([cardSupport, cardMarketing], \"grid\", true, { type: \"continue_conversation\", context: \"Explore this deep-dive area in more detail\" })\ncardSupport = CompositeCardItem(\"support-health\", supportHeader, [supportMetric, supportChart, supportList])\nsupportHeader = IconText(supportIcon, \"neutral\", \"m\", \"Support Health\", \"Ticket volume & resolution trends\", false, \"horizontal\")\nsupportIcon = Icon(\"headphones\", \"communication\")\nsupportMetric = MetricIndicatorInline(\"94.2% CSAT\", \"Customer Satisfaction Score\", { direction: \"up\", value: 2.1 })\nsupportChart = BarChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [openSeries, resolvedSeries], \"grouped\", \"Month\", \"Tickets\")\nopenSeries = Series(\"Opened\", [341, 327, 308, 289])\nresolvedSeries = Series(\"Resolved\", [319, 318, 301, 283])\nsupportList = EntityList([sup1, sup2, sup3], \"small\")\nsup1 = { left: \"Avg. Resolution Time\", right: \"4h 12m\", rightVariant: \"text\" }\nsup2 = { left: \"First Contact Resolution\", right: \"78.4%\", rightVariant: \"number\" }\nsup3 = { left: \"Escalation Rate\", right: \"6.2%\", rightVariant: \"number\" }\ncardMarketing = CompositeCardItem(\"marketing-roi\", marketingHeader, [marketingMetric, marketingChart, marketingList])\nmarketingHeader = IconText(marketingIcon, \"neutral\", \"m\", \"Marketing ROI\", \"Spend vs. pipeline generated\", false, \"horizontal\")\nmarketingIcon = Icon(\"megaphone\", \"communication\")\nmarketingMetric = MetricIndicatorInline(\"3.8x Blended ROI\", \"Return on Ad Spend\", { direction: \"up\", value: 0.4 })\nmarketingChart = AreaChart([\"Jan\", \"Feb\", \"Mar\", \"Apr\"], [spendSeries, pipelineSeries], \"natural\", \"Month\", \"Value ($k)\")\nspendSeries = Series(\"Ad Spend\", [44.0, 46.8, 49.2, 51.6])\npipelineSeries = Series(\"Pipeline Generated\", [158.2, 171.5, 184.9, 196.1])\nmarketingList = EntityList([mkt1, mkt2, mkt3], \"small\")\nmkt1 = { left: \"Total Ad Spend (Apr)\", right: \"$51,600\", rightVariant: \"number\" }\nmkt2 = { left: \"Cost per Lead\", right: \"$48.20\", rightVariant: \"number\" }\nmkt3 = { left: \"Top Channel\", right: \"Organic Search\", rightVariant: \"text\" }\nactionButtons = Buttons([btnChannels, btnForecast], \"row\")\nbtnChannels = Button(\"Break Down by Channel\", { type: \"continue_conversation\", context: \"Break down this month's revenue by acquisition channel\" }, \"primary\")\nbtnForecast = Button(\"Forecast Next Quarter\", { type: \"continue_conversation\", context: \"Forecast revenue and active users for next quarter\" }, \"secondary\")"}, +{"name":"chat-example-3","input":"Example 3 — Form response (help-me-choose/plan asks: inspiration cards FIRST, then a compact form). The inspiration-card images below came from an image tool call — include such cards ONLY when you have real URLs; with no real URLs, start directly with the form:\n\nroot = Card([header, intro, inspoCards, form])\nheader = CardHeader(\"Plan Your Trip\", \"A few ideas to spark inspiration — then tell me your preferences\")\nintro = TextContent(\"Tap a style to jump straight in, or fill the quick form below for a tailored plan.\")\ninspoCards = VisualCardBlock([insp1, insp2], \"grid\", true, { type: \"continue_conversation\", context: \"Plan me a trip in this style with destinations, itinerary, and costs\" })\ninsp1 = VisualCardItem(insp1body, \"inspo-beach\", \"https://www.travelandleisure.com/thmb/cuAB7XMQ6s_Gji-no956KNopT7M=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/TAL-maldives-TROPVACAY0325-1b5047d5931d4850b47d082966f9f563.jpg\", insp1tag, \"Maldives overwater villas\")\ninsp1body = BoldText(\"text\", \"Tropical Beach Escape\", \"Overwater villas & snorkeling\")\ninsp1tag = Tag(\"Relaxation\", insp1icon, \"sm\", \"info\")\ninsp1icon = Icon(\"umbrella\", \"travel\")\ninsp2 = VisualCardItem(insp2body, \"inspo-mountain\", \"https://www.salkantaytrekmachu.com/img/adventure-travel-peru-032.jpg\", insp2tag, \"Trekking in the Peruvian Andes\")\ninsp2body = BoldText(\"text\", \"Mountain Adventure\", \"Trekking & epic views\")\ninsp2tag = Tag(\"Active\", insp2icon, \"sm\", \"warning\")\ninsp2icon = Icon(\"mountain\", \"nature\")\nform = Form(\"trip-planner\", formButtons, [fcDestination, fcDates, fcTravellers, fcTripType, fcBudget, fcStay, fcNotes])\nformButtons = Buttons([btnSubmit, btnSkip], \"row\")\nbtnSubmit = Button(\"Plan My Trip\", { type: \"continue_conversation\", context: \"Help me plan a trip based on my form submission\" }, \"primary\")\nbtnSkip = Button(\"Just Surprise Me\", { type: \"continue_conversation\", context: \"Skip the form and surprise me with a destination and itinerary\" }, \"secondary\")\nfcDestination = FormControl(\"Destination\", destinationInput, \"Leave blank if you'd like suggestions\")\ndestinationInput = Input(\"destination\", \"e.g. Tokyo, Japan — or leave blank\", \"text\")\nfcDates = FormControl(\"Travel Dates\", datesPicker, \"Select your start and end dates\")\ndatesPicker = DatePicker(\"travel-dates\", \"range\", { required: true })\nfcTravellers = FormControl(\"Number of Travellers\", travellersSelect, \"How many people are travelling?\")\ntravellersSelect = Select(\"num-travellers\", [tr1, tr2, tr3, tr4], \"Select number of travellers\", { required: true })\ntr1 = SelectItem(\"1\", \"1 — Solo\")\ntr2 = SelectItem(\"2\", \"2 — Couple\")\ntr3 = SelectItem(\"3-4\", \"3–4 People\")\ntr4 = SelectItem(\"5+\", \"5+ People\")\nfcTripType = FormControl(\"Trip Type\", tripTypeCards, \"What kind of trip are you planning?\")\ntripTypeCards = OptionCards(\"trip-type\", \"single\", [oc1, oc2, oc3, oc4], { required: true })\noc1 = OptionCard(\"adventure\", \"Adventure\", \"Hiking, trekking & outdoor activities\", oc1icon)\noc1icon = Icon(\"mountain\", \"nature\")\noc2 = OptionCard(\"beach\", \"Beach & Relaxation\", \"Sun, sand & leisure\", oc2icon)\noc2icon = Icon(\"waves\", \"nature\")\noc3 = OptionCard(\"cultural\", \"Cultural & Historical\", \"Museums, heritage & local experiences\", oc3icon)\noc3icon = Icon(\"landmark\", \"buildings\")\noc4 = OptionCard(\"city\", \"City Break\", \"Urban exploration & nightlife\", oc4icon)\noc4icon = Icon(\"building-2\", \"buildings\")\nfcBudget = FormControl(\"Estimated Budget (per person)\", budgetSlider, \"Drag to set your per-person budget in USD\")\nbudgetSlider = Slider(\"budget\", \"discrete\", 500, 10000, 500, [2500], \"Budget (USD)\")\nfcStay = FormControl(\"Accommodation Preference\", stayChips, \"Select all that apply\")\nstayChips = Chips(\"accommodation\", \"multiple\", [ch1, ch2, ch3, ch4], {}, [\"hotel\"])\nch1 = ChipItem(\"hotel\", \"Hotel\", ch1icon)\nch1icon = Icon(\"building\", \"buildings\")\nch2 = ChipItem(\"resort\", \"Resort\", ch2icon)\nch2icon = Icon(\"umbrella\", \"travel\")\nch3 = ChipItem(\"airbnb\", \"Vacation Rental\", ch3icon)\nch3icon = Icon(\"home\", \"home\")\nch4 = ChipItem(\"camping\", \"Camping / Glamping\", ch4icon)\nch4icon = Icon(\"tent\", \"nature\")\nfcNotes = FormControl(\"Special Requests or Notes\", notesArea, \"Any dietary needs, accessibility requirements, or specific interests?\")\nnotesArea = TextArea(\"special-requests\", \"e.g. vegetarian meals, wheelchair access, honeymoon surprise...\", 4)"}, +{"name":"chat-example-4","input":"Example 4 — Recommendations with images and links (same pattern for products, movies, restaurants, articles):\n\nroot = Card([header, intro, posters, linksHeader, trackCards], [src1, src2])\nheader = CardHeader(\"Retro-Energetic Indian Tracks\", \"New Hindi releases with 80s/90s dance DNA\")\nintro = TextContent(\"These recent tracks channel retro synths and 90s party percussion [1][2]. Tap a poster to explore a track, or use its button to watch the exact official video.\")\nposters = VisualCardBlock([v1, v2], \"grid\", true, { type: \"continue_conversation\", context: \"Tell me more about this track and its retro influences\" })\nv1 = VisualCardItem(v1body, \"tamma\", \"https://i.ytimg.com/vi/PQHeOb0Q9oo/hq720.jpg\", v1tag, \"Tamma Tamma video poster\")\nv1body = BoldText(\"text\", \"Tamma Tamma\", \"Dhurandhar · Ranveer Singh\")\nv1tag = Tag(\"80s Electro-Disco\", v1icon, \"sm\", \"success\")\nv1icon = Icon(\"disc-3\", \"multimedia\")\nv2 = VisualCardItem(v2body, \"sajan\", \"https://i.ytimg.com/vi/mLz-qBiRnl8/hq720.jpg\", v2tag, \"Sajan Re video poster\")\nv2body = BoldText(\"text\", \"Sajan Re\", \"Nora Fatehi · Badshah\")\nv2tag = Tag(\"Synthwave Electro\", v2icon, \"sm\", \"info\")\nv2icon = Icon(\"music\", \"multimedia\")\nlinksHeader = InlineHeader(\"Watch the Exact Videos\", \"Each button opens that track's official video\")\ntrackCards = CompositeCardBlock([t1, t2], \"grid\", true)\nt1 = CompositeCardItem(\"t-tamma\", t1h, [t1body, t1tags], { button: t1btn })\nt1h = IconText(t1icon, \"neutral\", \"m\", \"Tamma Tamma\", \"Bappi Lahiri classic, electro-funk rework\", true, \"horizontal\")\nt1icon = Icon(\"disc-3\", \"multimedia\")\nt1body = Text(\"text\", \"Heavy analog synths and brass over a fast disco groove.\", \"Retro Electro-Disco\")\nt1tags = TagBlock([\"2026 Film Hit\", \"Peak Party\"])\nt1btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }, \"primary\")\nt2 = CompositeCardItem(\"t-sajan\", t2h, [t2body, t2tags], { button: t2btn })\nt2h = IconText(t2icon, \"neutral\", \"m\", \"Sajan Re\", \"Nora Fatehi · Badshah · Sanjoy\", true, \"horizontal\")\nt2icon = Icon(\"music\", \"multimedia\")\nt2body = Text(\"text\", \"Synthwave melody hooks over a modern club beat.\", \"Retro-Fusion Electro\")\nt2tags = TagBlock([\"Club Anthem\", \"Nora x Badshah\"])\nt2btn = Button(\"Watch on YouTube\", { type: \"open_url\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }, \"primary\")\nsrc1 = { title: \"Tamma Tamma (Full Video) - Dhurandhar\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=PQHeOb0Q9oo\" }\nsrc2 = { title: \"Sajan Re (Official Music Video)\", sourceName: \"YouTube (T-Series)\", url: \"https://www.youtube.com/watch?v=COUSCnFazzc\" }"}, +{"name":"chat-example-5","input":"Example 5 — Table with follow-ups:\n\nroot = Card([title, tbl, followUps])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\"]\nusers = [15.7, 14.2, 12.1]\nyears = [1991, 1995, 1995]\nfollowUps = FollowUpBlock([fu1, fu2])\nfu1 = FollowUpItem(\"Tell me more about Python\")\nfu2 = FollowUpItem(\"Show me a JavaScript comparison\")"} ] diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/openui-examples.json b/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/openui-examples.json index 8afad79c5a..a6b62cfd52 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/openui-examples.json +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/Fixtures/openui-examples.json @@ -1,26 +1,8 @@ [ - { - "name": "openui-example-1", - "input": "Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]" - }, - { - "name": "openui-example-2", - "input": "Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])" - }, - { - "name": "openui-example-3", - "input": "Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])" - }, - { - "name": "openui-example-4", - "input": "Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]" - }, - { - "name": "openui-example-5", - "input": "Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")" - }, - { - "name": "openui-example-6", - "input": "Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])" - } +{"name":"openui-example-1","input":"Example 1 — Table (column-oriented):\n\nroot = Stack([title, tbl])\ntitle = TextContent(\"Top Languages\", \"large-heavy\")\ntbl = Table([Col(\"Language\", langs), Col(\"Users (M)\", users), Col(\"Year\", years)])\nlangs = [\"Python\", \"JavaScript\", \"Java\", \"TypeScript\", \"Go\"]\nusers = [15.7, 14.2, 12.1, 8.5, 5.2]\nyears = [1991, 1995, 1995, 2012, 2009]"}, +{"name":"openui-example-2","input":"Example 2 — Bar chart:\n\nroot = Stack([title, chart])\ntitle = TextContent(\"Q4 Revenue\", \"large-heavy\")\nchart = BarChart(labels, [s1, s2], \"grouped\")\nlabels = [\"Oct\", \"Nov\", \"Dec\"]\ns1 = Series(\"Product A\", [120, 150, 180])\ns2 = Series(\"Product B\", [90, 110, 140])"}, +{"name":"openui-example-3","input":"Example 3 — Form with validation:\n\nroot = Stack([title, form])\ntitle = TextContent(\"Contact Us\", \"large-heavy\")\nform = Form(\"contact\", btns, [nameField, emailField, countryField, msgField])\nnameField = FormControl(\"Name\", Input(\"name\", \"Your name\", \"text\", { required: true, minLength: 2 }))\nemailField = FormControl(\"Email\", Input(\"email\", \"you@example.com\", \"email\", { required: true, email: true }))\ncountryField = FormControl(\"Country\", Select(\"country\", countryOpts, \"Select...\", { required: true }))\nmsgField = FormControl(\"Message\", TextArea(\"message\", \"Tell us more...\", 4, { required: true, minLength: 10 }))\ncountryOpts = [SelectItem(\"us\", \"United States\"), SelectItem(\"uk\", \"United Kingdom\"), SelectItem(\"de\", \"Germany\")]\nbtns = Buttons([Button(\"Submit\", Action([@ToAssistant(\"Submit\")]), \"primary\"), Button(\"Cancel\", Action([@ToAssistant(\"Cancel\")]), \"secondary\")])"}, +{"name":"openui-example-4","input":"Example 4 — Tabs with mixed content:\n\nroot = Stack([title, tabs])\ntitle = TextContent(\"React vs Vue\", \"large-heavy\")\ntabs = Tabs([tabReact, tabVue])\ntabReact = TabItem(\"react\", \"React\", reactContent)\ntabVue = TabItem(\"vue\", \"Vue\", vueContent)\nreactContent = [TextContent(\"React is a library by Meta for building UIs.\"), Callout(\"info\", \"Note\", \"React uses JSX syntax.\")]\nvueContent = [TextContent(\"Vue is a progressive framework by Evan You.\"), Callout(\"success\", \"Tip\", \"Vue has a gentle learning curve.\")]"}, +{"name":"openui-example-5","input":"Example 5 — KPI and product cards:\n\nroot = Stack([kpiHeader, kpiBlock, productsHeader, productCards])\nkpiHeader = InlineHeader(\"This Month\", \"Key account metrics\")\nkpiBlock = SnippetCardBlock([kpi1, kpi2, kpi3])\nkpi1 = SnippetCardItem(\"revenue\", kpi1lhs, kpi1rhs)\nkpi1lhs = IconText(kpi1icon, \"neutral\", \"m\", \"Revenue\", \"Month to date\", false, \"horizontal\")\nkpi1icon = Icon(\"circle-dollar-sign\", \"finance\")\nkpi1rhs = BoldText(\"number\", \"$48,200\", \"+8.1%\", \"metric\")\nkpi2 = SnippetCardItem(\"active-users\", kpi2lhs, kpi2rhs)\nkpi2lhs = IconText(kpi2icon, \"neutral\", \"m\", \"Active Users\", \"This month\", false, \"horizontal\")\nkpi2icon = Icon(\"users\", \"people\")\nkpi2rhs = BoldText(\"number\", \"1,204\", \"+3.4%\", \"metric\")\nkpi3 = SnippetCardItem(\"churn\", kpi3lhs, kpi3rhs)\nkpi3lhs = IconText(kpi3icon, \"neutral\", \"m\", \"Churn\", \"This month\", false, \"horizontal\")\nkpi3icon = Icon(\"user-minus\", \"people\")\nkpi3rhs = BoldText(\"number\", \"1.8%\", \"-0.3%\", \"metric\")\nproductsHeader = InlineHeader(\"Top Products\", \"By units sold\")\nproductCards = CompositeCardBlock([p1, p2])\np1 = CompositeCardItem(\"widget-pro\", p1header, [p1body], p1footer)\np1header = IconText(p1icon, \"neutral\", \"m\", \"Widget Pro\", \"Best seller\", true, \"horizontal\")\np1icon = Icon(\"package\", \"shopping\")\np1body = MetricIndicatorInline(\"2,410 units\", \"Sold this month\", { direction: \"up\", value: 12 })\np1footer = { price: BoldText(\"text\", \"$29.00\"), button: p1btn }\np1btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Pro\")]), \"secondary\")\np2 = CompositeCardItem(\"widget-mini\", p2header, [p2body], p2footer)\np2header = IconText(p2icon, \"neutral\", \"m\", \"Widget Mini\", \"New arrival\", true, \"horizontal\")\np2icon = Icon(\"box\", \"shopping\")\np2body = MetricIndicatorInline(\"980 units\", \"Sold this month\", { direction: \"up\", value: 4 })\np2footer = { price: BoldText(\"text\", \"$14.00\"), button: p2btn }\np2btn = Button(\"View Details\", Action([@ToAssistant(\"Show details for Widget Mini\")]), \"secondary\")"}, +{"name":"openui-example-6","input":"Example 6 — Editable table and a selection form:\n\nroot = Stack([tableHeader, editTable, formHeader, prefsForm])\ntableHeader = InlineHeader(\"Team Roster\", \"Click a cell to edit\")\neditTable = EditableTable(\"roster\", [colName, colRole, colStart], [row1, row2])\ncolName = { type: \"text\", key: \"name\", header: \"Name\" }\ncolRole = { type: \"select\", key: \"role\", header: \"Role\", options: [roleEng, roleDesign] }\nroleEng = { value: \"eng\", label: \"Engineering\" }\nroleDesign = { value: \"design\", label: \"Design\" }\ncolStart = { type: \"date-single\", key: \"start\", header: \"Start Date\" }\nrow1 = { id: \"1\", values: [\"Alex Kim\", \"eng\", \"2024-01-15\"] }\nrow2 = { id: \"2\", values: [\"Jamie Lee\", \"design\", \"2024-03-02\"] }\nformHeader = InlineHeader(\"Preferences\", \"Tell us how you like to work\")\nprefsForm = Form(\"prefs\", formButtons, [fc1, fc2])\nfc1 = FormControl(\"Working Style\", styleCards, \"Pick the one that fits best\")\nstyleCards = OptionCards(\"style\", \"single\", [style1, style2])\nstyle1 = OptionCard(\"focused\", \"Deep Focus\", \"Long uninterrupted blocks\", style1icon)\nstyle1icon = Icon(\"target\", \"tools\")\nstyle2 = OptionCard(\"collab\", \"Collaborative\", \"Frequent pairing and syncs\", style2icon)\nstyle2icon = Icon(\"users\", \"people\")\nfc2 = FormControl(\"Tools\", toolChips, \"Select all that apply\")\ntoolChips = Chips(\"tools\", \"multiple\", [tool1, tool2, tool3])\ntool1 = ChipItem(\"figma\", \"Figma\", tool1icon)\ntool1icon = Icon(\"figma\", \"design\")\ntool2 = ChipItem(\"slack\", \"Slack\", tool2icon)\ntool2icon = Icon(\"message-square\", \"communication\")\ntool3 = ChipItem(\"notion\", \"Notion\", tool3icon)\ntool3icon = Icon(\"notebook\", \"text\")\nformButtons = Buttons([Button(\"Save\", Action([@ToAssistant(\"Save preferences\")]), \"primary\")])"} ] From 0959ff1317de2da2e5471da96d4251b4b9b1423f Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Thu, 8 Oct 2026 15:46:10 +0530 Subject: [PATCH 50/52] fix(swift-lang): let a mouse scroll card carousels Card blocks laid out as a carousel had no step buttons, as in react-ui, so on a Mac with a mouse the cards past the edge were out of reach: the wheel scrolls up and down, and there's no shift-scrolling or scrollbar to fall back on like in a browser. Show the Carousel's buttons while a pointer is over the row. --- packages/swift-lang/README.md | 1 + .../Components/LayoutComponents.swift | 25 +++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/packages/swift-lang/README.md b/packages/swift-lang/README.md index db0d1421c8..10c230d93c 100644 --- a/packages/swift-lang/README.md +++ b/packages/swift-lang/README.md @@ -245,6 +245,7 @@ Conform your own type to `ToolProvider` for other backends. - `$$` math in text content shows as source; there's no native TeX renderer. - Code is highlighted with Prism's `vscDarkPlus` and `oneLight` colors by a small built-in tokenizer covering common languages (C-family, JSON, markup, Python, Ruby, shell, YAML, SQL), not by Prism's grammars. - Touch has no hover, so a chart's tooltip opens on a tap and stays until the same spot is tapped again (or another chart's opens), where react-ui shows it while a finger moves. Hover states need a pointer: the Mac, or an iPad with a trackpad. +- Card blocks laid out as a carousel show the Carousel's step buttons while a pointer is over them. A mouse wheel only scrolls up and down, and there's no shift-scrolling or scrollbar to fall back on like in a browser, so react-ui's button-less card carousels can't be scrolled with a mouse otherwise. - Editable table cells are always text fields, which suits touch, rather than react-ui's select-then-edit cells. With a keyboard, Up and Down move between rows and Enter moves down; Escape doesn't undo an edit. - Crowded chart axes keep thinning their labels until the longest fits, down to three labels. react-ui stops thinning once each label has 40px and truncates the rest. - A visual card whose text block came out empty (say, a loop variable used outside its `@Each`) shows just its photo, where react-ui draws an empty panel over it. diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift index 793eb2d2fb..984aa34ba8 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/LayoutComponents.swift @@ -510,15 +510,19 @@ struct CarouselView: View { } /// A horizontal row that scrolls like react-ui's carousels: items snap to the -/// leading edge, an edge fades out where there's more to scroll, and optional -/// buttons step one item at a time. Whether it can scroll only drives the -/// fades and buttons, never a size, so it can't feed back into layout. +/// leading edge, an edge fades out where there's more to scroll, and buttons +/// step one item at a time. Whether it can scroll only drives the fades and +/// buttons, never a size, so it can't feed back into layout. struct CarouselScroller: View { let count: Int var spacing: CGFloat /// How far an edge fades out: 40 for react-ui's Carousel, its `space-3xl` /// (48) for card blocks. var fade: CGFloat + /// Shows the buttons all the time, as react-ui's Carousel does. Card blocks + /// show them only while a pointer is over the row: a mouse wheel scrolls + /// up and down, so without them a mouse can't reach the cards past the + /// edge (a browser has shift-scrolling and a scrollbar for that). var showsButtons = false /// Stretches items to the tallest one, as a flex row does. var equalHeights = false @@ -527,11 +531,16 @@ struct CarouselScroller: View { @State private var position: Int? @State private var content = CGRect.zero @State private var visibleWidth: CGFloat = 0 + @State private var hoveringRow = false + /// The buttons hang half outside the row, so the pointer can be on one + /// without being over the row. + @State private var hoveringButton = false @Environment(\.openUITheme) private var theme var body: some View { let canScrollBack = content.minX < -1 let canScrollOn = content.maxX > visibleWidth + 1 + let buttons = showsButtons || hoveringRow || hoveringButton ScrollView(.horizontal, showsIndicators: false) { HStack(alignment: .top, spacing: spacing) { ForEach(0..: View { .frame(width: canScrollOn ? fade : 0) } } + .onHover { hoveringRow = $0 } .overlay(alignment: .leading) { - if showsButtons && canScrollBack { stepButton(-1) } + if buttons && canScrollBack { stepButton(-1) } } .overlay(alignment: .trailing) { - if showsButtons && canScrollOn { stepButton(1) } + if buttons && canScrollOn { stepButton(1) } } + .animation(.easeOut(duration: 0.15), value: buttons) } /// react-ui's small square secondary button, half over the edge. @@ -590,6 +601,10 @@ struct CarouselScroller: View { .shadow(color: .black.opacity(0.08), radius: 3, y: 1) } .buttonStyle(.plain) + .onHover { hoveringButton = $0 } + // A button that goes away under the pointer (the row reached its end) + // never hears the pointer leave. + .onDisappear { hoveringButton = false } .accessibilityLabel(step < 0 ? "Previous" : "Next") .offset(x: step < 0 ? -12 : 12) } From 0f9f68afda627201d85012de8a95fb73cf027f81 Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Fri, 9 Oct 2026 08:21:26 +0530 Subject: [PATCH 51/52] fix(swift-lang): keep a slider whose range is shorter than a step from crashing SwiftUI's Slider traps ("max stride must be positive") unless its range holds a whole step. A streamed slider hits that when max arrives cut short below min (Slider("b", "discrete", 2000, 800 before the 0 of 8000), and a response can give a step wider than the range. The track stays idle until there's a range to move in. --- .../Sources/OpenUISwiftUI/Components/FormComponents.swift | 6 ++++++ .../swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift index 57cf9c1e63..99758e8928 100644 --- a/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift +++ b/packages/swift-lang/Sources/OpenUISwiftUI/Components/FormComponents.swift @@ -507,6 +507,12 @@ struct SliderView: View { upper: RangeSlider.clamp(max(current[0], current[1]), to: minimum...maximum), bounds: minimum...maximum, step: step ) { set([$0, $1]) } + } else if maximum - minimum < step { + // SwiftUI's Slider traps unless its range holds a whole step. Mid-stream + // `max` can be cut short below `min` ("8000" arrives as "800"), and a + // response can give a step wider than the range, so the track stays + // idle until there's a range to move in. + Slider(value: .constant(0), in: 0...1).disabled(true) } else if (maximum - minimum) / step <= 100 { Slider( value: Binding( diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 5d096700c3..7e98ecfb4c 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -220,6 +220,10 @@ import Testing #"Slider("s", "discrete", 0, 1000000, 0.001)"#, #"Slider("s", "continuous", 0/0, 10, 1)"#, #"Slider("s", "continuous", 0, 100, 1, [10, 1e999])"#, + // Mid-stream, `max` can be cut short below `min` ("8000" arrives as "800"). + #"Slider("s", "discrete", 2000, 800)"#, + #"Slider("s", "continuous", 5, 5)"#, + #"Slider("s", "discrete", 0, 10, 50)"#, #"BarChart(["A"], [Series("S", [1])], "grouped", "x", "y", 1e999)"#, #"RadarChart(["A", "B", "C"], [Series("S", [1, 1e999, 3])])"#, #"ScatterChart([ScatterSeries("S", [Point(1, 2), Point(0/0, 1)])])"#, From 7160f33479cd608858edff8f0e27aa58ee5d0eca Mon Sep 17 00:00:00 2001 From: NandishwarSingh <157561951+NandishwarSingh@users.noreply.github.com> Date: Fri, 9 Oct 2026 08:21:27 +0530 Subject: [PATCH 52/52] test(swift-lang): compile the renderer tests for iOS again The flow layout test hosts its view in an NSHostingView, so like the other AppKit tests it only builds on macOS. --- .../OpenUISwiftUITests/RendererTests.swift | 56 ++++++++++--------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift index 7e98ecfb4c..d3f84eb971 100644 --- a/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift +++ b/packages/swift-lang/Tests/OpenUISwiftUITests/RendererTests.swift @@ -879,34 +879,36 @@ let globalTestLibrary = SwiftUILibrary( } } -/// Wrapping rows (tags, chips, legends) never let a child spill past the -/// container: one wider than a row gets the row's width. -@MainActor -@Suite struct FlowLayoutTests { - @Test func capsWideChildrenAtTheRowWidth() { - final class Box { var width: CGFloat = 0 } - let box = Box() - let host = NSHostingView( - rootView: FlowLayout { - Text("Short") - Text(String(repeating: "wide ", count: 60)) - .lineLimit(1) - .onGeometryChange(for: CGFloat.self) { - $0.size.width - } action: { - box.width = $0 - } - } - .frame(width: 200)) - let window = NSWindow( - contentRect: NSRect(x: 0, y: 0, width: 200, height: 200), styleMask: [.borderless], - backing: .buffered, defer: false) - window.contentView = host - RunLoop.main.run(until: Date().addingTimeInterval(0.2)) - #expect(box.width > 150) - #expect(box.width <= 200) +#if canImport(AppKit) + /// Wrapping rows (tags, chips, legends) never let a child spill past the + /// container: one wider than a row gets the row's width. + @MainActor + @Suite struct FlowLayoutTests { + @Test func capsWideChildrenAtTheRowWidth() { + final class Box { var width: CGFloat = 0 } + let box = Box() + let host = NSHostingView( + rootView: FlowLayout { + Text("Short") + Text(String(repeating: "wide ", count: 60)) + .lineLimit(1) + .onGeometryChange(for: CGFloat.self) { + $0.size.width + } action: { + box.width = $0 + } + } + .frame(width: 200)) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 200, height: 200), styleMask: [.borderless], + backing: .buffered, defer: false) + window.contentView = host + RunLoop.main.run(until: Date().addingTimeInterval(0.2)) + #expect(box.width > 150) + #expect(box.width <= 200) + } } -} +#endif /// The flex layout behind openuiLibrary's Stack and Card, against what CSS /// flexbox does with react-ui's styles.